Strong reference(强引用)
在Java中,非静态内部类会在其整个生命周期中持有对它外部类的强引用。
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new MyAsyncTask(this).execute();
}
private class MyAsyncTask extends AsyncTask {
@Override
protected Object doInBackground(Object[] params) {
// 模拟耗时任务
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return doSomeStuff();
}
private Object doSomeStuff() {
return new Object();
}
@Override
protected void onPostExecute(Object object) {
super.onPostExecute(object);
// 更新UI
}
}
}
这段代码里,MyAsyncTask会跟随Activity的onCreate去创建并开始执行一个长时间的耗时任务,并在耗时任务完成后去更新MainActivity中的UI。这是一个很常见的使用场景,却会导致内存泄露问题。
MainActivity被销毁时,MyAsyncTask中的耗时任务可能仍没有执行完成,所以MyAsyncTask会一直存活。此时,由于MyAsyncTask持有着其外部类,即MainActivity的引用,将导致MainActivity不能被垃圾回收。如果MainActivity中还持有着Bitmap等大对象,反复进出这个页面几次可能就会出现OOM Crash了。
WeakReference(弱引用)
弱引用通过类WeakReference来表示。弱引用并不能阻止垃圾回收。如果使用一个强引用的话,只要该引用存在,那么被引用的对象是不能被回收的。弱引用则没有这个问题。在垃圾回收器运行的时候,如果对一个对象的所有引用都是弱引用的话,该对象会被回收。
我们调整一下上面例子中的代码,使用弱引用去避免内存泄露:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new MyAsyncTask(this).execute();
}
private static class MyAsyncTask extends AsyncTask {
private WeakReference<MainActivity> mainActivity;
public MyAsyncTask(MainActivity mainActivity) {
this.mainActivity = new WeakReference<>(mainActivity);
}
@Override
protected Object doInBackground(Object[] params) {
// 模拟耗时任务
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return doSomeStuff();
}
private Object doSomeStuff() {
//do something to get result
return new Object();
}
@Override
protected void onPostExecute(Object object) {
super.onPostExecute(object);
if (mainActivity.get() != null){
// 更新UI
}
}
}
}
大家可以注意到,主要的不同点在于,我们把MyAsyncTask改为了静态内部类,并且其对外部类MainActivity的引用换成了:
private WeakReference<MainActivity> mainActivity;
当MainActivity destroy的时候,由于MyAsyncTask是通过弱引用的方式持有MainActivity,所以并不会阻止MainActivity被垃圾回收器回收,也就不会有内存泄露产生了。