原文地址:https://medium.com/google-developer-experts/weakreference-in-android-dd1e66b9be9d#.n8z6g146q
我的一个同事最近提到他们看到一种观点说:
如果你是一个Android开发者但你没有使用WeakReferences,那么你就有问题。
我个人认为这不仅是一个错误的观点,也是百分百的误导。WeakReference应该是修复内存泄漏的最后手段。
今天我看了一篇Google开发专家Enrique López Mañas的文章
Finally understanding how references work in Android and Java
这是一篇很好的文章,它通过举例总结了引用在Java中是如何运作的。
文章中既没有说我们必须要使用WeakReference,也没有给出任何替代的方案。我觉得我需要提供一个替代方案来说明WeakReference不是必须的。
就算你没有使用WeakReference,你也没有任何问题。
我相信在任何可能的地方都使用WeakReference并不是最好的方式。使用WeakReference来修复内存泄漏表明了模型或架构中有缺陷。
虽然给出的文章中的例子修复了潜在的内存泄漏,但这还有其他的方式。我会给出两个当你有一个长时的后台任务时如何避免内存泄漏的实例。
一个使用AsyncTask来避免内存泄漏的简单例子如下:
这是我的Activity:
public class MainActivity extends Activity {
private MyAsyncTask task;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
task = new MyAsyncTask();
task.setListener(createListener());
task.execute();
}
@Override
protected void onDestroy() {
task.setListener(null);
super.onDestroy();
}
private MyAsyncTask.Listener createListener() {
return new MyAsyncTask.Listener() {
@Override
public void onSuccess(Object object) {
// adapt contents
}
};
}
}
这是我的AsyncTask:
class MyAsyncTask extends AsyncTask {
private Listener listener;
@Override
protected Object doInBackground(Object[] params) {
return doSomeStuff();
}
private Object doSomeStuff() {
//do something to get result
return new Object();
}
@Override
protected void onPostExecute(Object object) {
if (listener != null) {
listener.onSuccess(object);
}
}
public void setListener(Listener listener) {
this.listener = listener;
}
interface Listener {
void onSuccess(Object object);
}
}
当然这种方式非常基础,但我认为它足够用来展示另一种解决办法。
这里是另一种使用RxJava的简单实现,我们依然没有使用WeakReference。
public class MainActivity extends Activity {
private Subscription subscription;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
subscription = Observable
.fromCallable(new Callable<Object>() {
@Override
public Object call() throws Exception {
return doSomeStuff();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Object>() {
@Override
public void call(Object o) {
// adapt contents
}
});
}
private Object doSomeStuff() {
//do something to get result
return new Object();
}
@Override
protected void onDestroy() {
subscription.unsubscribe();
super.onDestroy();
}
}
需要注意的是如果我们没有取消订阅Subscription的话依然会有内存泄漏的情况。
最后我想列举一些Novoda中的示例项目。它们有很棒的资源可以学习。如你所料,它们都没有使用任何WeakReference :)
novoda/bonfire-firebase-sample
我相信将内部类设置为静态类是第一原则(就我而言)。特别是如果它们要在后台进行长时间操作时。最好的办法,我们可以将这些类变成完整的类。
使用非静态的内部类来执行长时操作永远是一个坏习惯,不仅仅限于Android。