Android内存溢出与优化(五)——防止static引用

来源:互联网 发布:淘宝改折扣影响权重吗 编辑:程序博客网 时间:2024/05/21 06:25

总篇地址:Android内存溢出与优化(零)——开题篇

前言:在Java中,如果将一个对象加上static修饰符,那么JVM虚拟机就会在内存中一直保留这个对象,这个对象不会被垃圾回收器清理,直到应用退出。为了达到目的,随意使用static修饰符是不好的表现。不过有时候又不得不使用static修饰,那么我们只用尽量避免消耗大内存的对象被static修饰或间接产生引用。下面开始Android中的代码讨论。

1.常用的Utils中的static修饰

为了方便调用,在Utils工具类中使用static修饰是我们常用的方式,不过可能存在一些问题,例如:

public class ToastUtil {    private static Toast toast;    public static void show(Context context, String message) {        if (toast == null) {            toast = Toast.makeText(context, message, Toast.LENGTH_SHORT);        } else {            toast.setText(message);        }              toast.show();    }}

分析:请看static修饰的toast对象,在show方法中这个对象同时对context持有了引用。toast是static修饰的,意味着toast将不会从内存中消失,那么其持有的引用对象context将一直保持强引用,也不会在内存中消失。如果传个占用大内存的Activity的context进来,那么将会导致大量的内存泄漏。

提供2种解决办法:
1. 将context改为context.getApplicationContext(),由于ApplicationContext是一个全局的context,会在app运行期间一直存在,就不存在内存泄露的问题了
2. 创建Application类,提供获取ApplicationContext的方法,直接在show方法中获取,不需要每次都传context了(推荐)
代码如下:

//Application类public class MyApplication extends Application {    private static Context context;    @Override    public void onCreate() {        super.onCreate();        context = getApplicationContext();    }    public static Context getContext(){        return context;    }}////Toast工具类public class ToastUtil {    private static Toast toast;    public static void show(String message) {        if (toast == null) {            toast = Toast.makeText(MyApplication.getContext(), message, Toast.LENGTH_SHORT);        } else {            toast.setText(message);        }              toast.show();    }}

2.单例模式中的static修饰

在单例中我也可能会有传入context这种对象,例如数据库Dao层的设计,如下:

1.AppDemo数据库创建的class

/** * AppDemo数据库创建 * @author ALion */public class AppDemoOpenHelper extends SQLiteOpenHelper {    public AppDemoOpenHelper(Context context) {        super(context, "appDemo.db", null, 1);    }    //数据库第一次创建调用    @Override    public void onCreate(SQLiteDatabase db) {        //字段:_id, name        String sql = "CREATE TABLE t_appDemo (" +                        "_id INTEGER PRIMARY KEY AUTOINCREAMENT" +                        "name VARCHAR(20)" +                    )";        db.execSQL(sql);    }    //数据库更新时    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {    }}

2.数据库Dao封装的class

/** * 数据库Dao封装 * @author ALion */public class AppDemoDao {    private static AppDemoDao sInstance = null;    public AppDemoOpenHelper mHelper;    private AppDemoDao(Context context) {        mHelper = new AppDemoOpenHelper(context);    }    public static AppDemoDao getInstance(Context context) {        if (sInstance == null) {            synchronized (AppDemoDao.class) {                if (sInstance == null)                    sInstance = new AppDemoDao(context);            }        }        return sInstance;    }    // TODO 增加    // TODO 删除    // TODO 修改    // TODO 查询}

分析:可以看到创建数据库的AppDemoOpenHelper类需要传入一个context对象,而在Dao封装层的AppDemoDao类中又使用了单例设计模式。代码中,sInstance对象使用了static修饰,其new AppDemoDao(context)需要传入一个context对象,context被sInstance持有了强引用,从而导致了context对象的内存泄露。

解决方式同上,就不再给出代码了。

阅读全文
0 0
原创粉丝点击