美文网首页
安卓引用类型之坑 强引用 软引用 弱引用 虚引用之分

安卓引用类型之坑 强引用 软引用 弱引用 虚引用之分

作者: 缝雨 | 来源:发表于2017-11-27 18:09 被阅读0次

    之前一直都是new对象的,压根就不知道什么引用之类的东西,直到用SharedPreference的时候,用到了OnSharedPreferenceChangeListener,被坑了一把,才了解到引用的概念,然后了解一番。初看觉得这东西好麻烦,仔细了解一下之后才发现,这东西在内存控制方面还是很重要,很实用的。

    事情是这个样子,我将一个值存到SharedPreference里面,如果其他的地方改变这个值,我需要将新的值给显示出来,一个很简单的逻辑,可做完之后发现运行的结果与实际情况并不是每次都相符的,经过打log发现,居然是,额,监听有时候有效,有时候无效,OnSharedPreferenceChangeListener没有被触发。
    第一次碰到这种监听无效的情况,很是一脸的懵逼。

    内部的项目的代码就不分享了,用一个demo来说明一下。
    点击Button,计数加1,将点击数存到SharedPreference中,用OnSharedPreferenceChangeListener来监听SharedPreference中值的变化,变化的时候将计数打印出来,运行一段时间会发现,OnSharedPreferenceChangeListener失效了。

    import android.content.SharedPreferences;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends AppCompatActivity {
    
        private SharedPreferences spJ;
        private SharedPreferences.Editor editor;
        private Button buttonNum;
        private int clickN;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            final int initTimes=0;
            clickN=initTimes;
            buttonNum=(Button)findViewById(R.id.Button_Num);
            spJ =getApplicationContext().getSharedPreferences("ClickN",MODE_PRIVATE);
            editor= spJ.edit();
    
            buttonNum.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    clickN++;
                    editor.putInt("times",clickN).commit();
                }
            });
    
            spJ.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() {
                @Override
                public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
                    Log.d("MainActivity", "onSharedPreferenceChanged: "+spJ.getInt("times",initTimes));
                }
            });
        }
    }
    
    
    
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.uidq0205.jtodo.MainActivity">
    
        <Button
            android:id="@+id/Button_Num"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="00"/>
    
    </LinearLayout>
    
    

    这让人很奇怪啊,于是就往源码里看,还好,刚一看,就看出了问题,“not currently store a strong reference to the listener”。继续了解之后,发现,原来是引用惹的祸。


    registerOnSharedPreferenceChangeListener.png

    强引用

    从名字也很好理解,就是很强的引用咯,那么有多强呢?即使在内存很不够用的时候,程序报出Out Of Memory错误,也不会回收强引用的对象的。这种我们在编程中用的是最广了,比如说new。

    软引用

    软引用,顾名思义,就是比较弱的一种引用,弱是相对于上一个来说的。这个还是比较讲义气的,当内存不够用的时候,他会牺牲自己,贡献出自己的内存,避免发生Out Of Memory。当内存足够时,他是比较安全的,并不会被回收掉。

    弱引用

    弱引用,就是比较弱咯,弱到什么程度呢,如果一不小心,被垃圾回收机制检测到,就有可能被回收,貌似跟此时内存够不够也没有关系。

    虚引用

    这个,就比较奇葩了,因为比弱还弱,弱到什么程度呢。对对象的生命周期没有影响,而且,无法通过弱引用得到对象,弱的不行不行的。它基本只有一个作用,在对象被回收的时候,得到一个系统通知,这一点,基本是它唯一可以被利用的一点。
    这一点怎么用呢,在需要对内存十分克制的开发中,这一点很重要,可以通过这一点来准确的判断对象是否被回收,来决定是否申请一个新的对象来占用内存。准确是相对通常用的finalize()方法来说的。
    finalize()被调用的时候,只是准备好释放存储空间,只有在下一次垃圾收集的过程中,对象的内存才会被清除掉,并不准确。还有一点,存在finalize()重写不规范的情况,如果在该方法中又创建了一个强引用来指向要被销毁的对象时,这个对象就重新复活了。
    而使用虚引用就不会存在这种问题,只有当对象占用的内存空间被清除的时候,才会返回系统通知,这个时候,被销毁的对象是不会被重新激活的。

    咋一看,会觉得区分起来蛮麻烦的,不过当你内存紧缺的时候就不会这么想了,哈哈。

    相关文章

      网友评论

          本文标题:安卓引用类型之坑 强引用 软引用 弱引用 虚引用之分

          本文链接:https://www.haomeiwen.com/subject/zwtdbxtx.html