Context内存泄漏问题

今天看了一篇介绍Context的文章,写的不错,里面有一段内容平时开发时候没有注意到,摘抄如下: 
在项目中,我们经常会遇到使用单例模式或者静态static变量,虽然使用静态类或者静态变量很方便,但是也潜在很多的内存泄漏问题

6.1静态资源导致的内存泄漏

你可能遇到以下这段代码:

public class MyCustomResource {
    //静态变量drawable
    private static Drawable drawable;

    public MyCustomResource(Context context) { //这个context对象就是Activity的Context
        Resources resources = context.getResources();
        drawable = resources.getDrawable(R.drawable.ic_launcher);
    }
}

请问,这段代码有什么问题?乍一看貌似没啥问题,挺好的啊!其实不然,主要的问题在于静态变量drawable这里,我们知道静态变量在整个应用的内存里只保存一份,一旦创建就不会释放该变量的内存,直到整个应用都销毁才会释放static静态变量的内存。可是以上drawable资源是由Context对象来获得,从而静态变量drawable会持有该Context对象的引用,也就意味着如果该Context对应的Activity退出finish掉的时候其实该Activity是不能完全释放内存的,因为静态变量drawable持有该Activity的Context。从而导致该Activity内存无法回收,导致内存泄漏隐患。因为Activity就是Context,所有Context的生命周期和Activity是一样长的,我们希望Activity退出时Context也释放内存,这样才不会导致内存泄漏隐患。那么以上这段代码是不安全的,如果代码必须要使用静态资源怎么办呢?其实我们可以这么修改:

Context包括三种:Activity、Service和Application,一般而言Context对象都是Activity的context,在一篇我的这篇文章https://mp.csdn.net/postedit/80222796讲到,一般就不要用Activity的context,容易出现内存泄漏的问题,尽量使用Application的Context。

public class MyCustomResource {
    //静态变量drawable
    private static Drawable drawable;

    public MyCustomResource(Context context) {
        Resources resources = (context.getApplicationContext()).getResources();
        drawable = resources.getDrawable(R.drawable.ic_launcher);
    }

}

这里我们修改成了使用getApplicationContext去获取App的资源。由上一小节可知getApplicationContext返回的对象是Application的Context,而Application的生命周期和整个应用是一样的,应用启动Application被创建,整个应用退出Application销毁。所以Application的Context的生命周期就是整个应用的生命周期,恰好可以用来获取静态资源。利用Application的Context就不会导致内存泄漏了。

6.2 单例模式导致内存泄漏

相信单例模式对开发者很有诱惑力吧!或多或少在项目中都有用过单例模式。你也可能见过一下这段代码:

public class CustomManager {
    private static CustomManager sInstance;
    public static CustomManager getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new CustomManager(context);
        }
        return sInstance;
    }

    private Context mContext;
    private CustomManager(Context context) {
        mContext = context;
    }
}

同样,以上代码也存在内存泄漏的隐患。因为单例模式使用的是静态类的方式,让该对象在整个应用的内存中保持一份该对象,从而减少对多次创建对象带来的资源浪费。同样的问题:在创建该单例的时候使用了生命周期端的Context对象的引用,如果你是在Application中创建以上单例的话是木有任何问题的。因为Application的Context生命周期是整个应用,和单例的生命周期一样,因此不会导致内存泄漏。但是,如果你是在Activity中创建以上单例的话,就会导致和6.1小节一样的问题—内存泄漏。所以我们同样可以将代码修改成如下:

public class CustomManager {
    private static CustomManager sInstance;
    public static CustomManager getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new CustomManager(context.getApplicationContext());
        }
        return sInstance;
    }

    private Context mContext;
    private CustomManager(Context context) {
        mContext = context;
    }
}

6.3 总结

以后在使用Context对象获取静态资源,创建单例对象或者静态方法的时候,请多考虑Context的生命周期,一定要记得不要使用Activity的Context,切记要使用生命周期长的Application的Context对象。但是并不是所有情况使用Application的Context对象,比如第4小节,在创建Dialog,View控件的时候都必须使用Activity的Context对象。

转载自:http://blog.csdn.net/feiduclear_up CSDN 废墟的树

猜你喜欢

转载自blog.csdn.net/cdaimadada/article/details/80488132
今日推荐