Android内存溢出与优化(五)——防止static引用
在Java中,如果将一个对象加上static修饰符,那么JVM虚拟机就会在内存中一直保留这个对象,这个对象不会被垃圾回收器清理,直到应用退出。为了达到目的,随意使用static修饰符是不好的表现。不过有时候又不得不使用static修饰,那么我们只用尽量避免消耗大内存的对象被static修饰。下面开始Android中的代码讨论。1.常用的Ut
前言:在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)