A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

在Android开发中,我们经常会使用到static来修饰我们的成员变量,其本意是为了让多个对象共用一份空间,节省内存,或者是使用单例模式,让该类只生产一个实例而在整个app中使用。然而在某些时候不恰当的使用或者是编程的不规范却会造成了内存泄露现象(java上的内存泄漏指内存得不到gc的及时回收,从而造成内存占用过多的现象)
大家好,我们主要分析的是static变量对activtiy的不恰当引用而造成的内存泄漏,因为对于同一个Activity页面一般每次打开时系统都会重新生成一个该activity的对象(standard模式下),而每个activity对象一般都含有大量的视图对象和bitmap对象,如果之前的activity对象不能得到及时的回收,从而就造成了内存的泄漏现象。
下面一边看代码一边讲解。
单例模式不正确的获取context
public class LoginManager {

    private Context context;
    private static LoginManager manager;

    public static LoginManager getInstance(Context context) {
        if (manager == null)
            manager = new LoginManager(context);
        return manager;
    }

    private LoginManager(Context context) {
        this.context = context;
    }
在LoginActivity中
public class LoginActivity extends Activity  {

    private LoginManager loginManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        loginManager = LoginManager.getInstance(this);
    }
这种方式大家应该一看就明白问题在哪里了,在LoginManager的单例中context持有了LoginActivity的this对象,即使登录成功后我们跳转到了其他Activity页面,LoginActivity的对象仍然得不到回收因为他被单例所持有,而单例的生命周期是同Application保持一致的。

正确的获取context的方式
public class LoginManager {

    private Context context;
    private static LoginManager manager;

    public static LoginManager getInstance(Context context) {
        if (manager == null)
            manager = new LoginManager(context);
        return manager;
    }

    private LoginManager(Context context) {
        this.context = context.getApplicationContext();
    }
修改方式也非常简单我们单例中context不再持有Activity的context而是持有Application的context即可,因为Application本来就是单例,所以这样就不会存在内存泄漏的的现象了。

单例模式中通过内部类持有activity对象
第一种方式内存泄漏太过与明显,相信大家都不会犯这种错误,接下来要介绍的这种泄漏方式会比较不那么容易发现,内部类的使用造成activity对象被单例持有。
还是看代码再分析,下面是一个单例的类:
public class TestManager {
    public static final TestManager INSTANCE = new TestManager();
    private List<MyListener> mListenerList;

    private TestManager() {
        mListenerList = new ArrayList<MyListener>();
    }

    public static TestManager getInstance() {
        return INSTANCE;
    }

    public void registerListener(MyListener listener) {
        if (!mListenerList.contains(listener)) {
            mListenerList.add(listener);
        }
    }
    public void unregisterListener(MyListener listener) {
        mListenerList.remove(listener);
    }
}

interface MyListener {
    public void onSomeThingHappen();
}
然后是activity:
public class TestActivity extends AppCompatActivity {

    private MyListener mMyListener=new MyListener() {
        @Override
        public void onSomeThingHappen() {
        }
    };
    private TestManager testManager=TestManager.getInstance();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        testManager.registerListener(mMyListener);
    }
}
我们知道在java中,非静态的内部类的对象都是会持有指向外部类对象的引用的,因此我们将内部类对象mMyListener让单例所持有时,由于mMyListener引用了我们的activity对象,因此造成activity对象也不能被回收了,从而出现内存泄漏现象。
修改以上代码,避免内存泄漏,在activity中添加以下代码:`
@Override
protected void onDestroy() {
    testManager.unregisterListener(mMyListener);
    super.onDestroy();
}


0 个回复

您需要登录后才可以回帖 登录 | 加入黑马