原文:You don’t have to use WeakReference to avoid memory leaks
我的一個同事最近提到他們看的一個演講,其中講到:
如果你是一個安卓開發者卻不使用弱引用,那麼你就有麻煩了。
我個人認為這不僅是一種錯誤觀點,而且相當誤導人。WeakReference(弱引用)應該是修復記憶體洩漏的最後手段。
然後今天,我看到了Enrique López Mañas釋出在Google Developers Experts專欄的一篇文章。
這是一篇總結Java引用的好文章。
這篇文章並沒有說必須使用弱引用,但是也沒有給出替代的方案。我覺得我必須給出其它的方法來闡明弱引用並不是必須使用。
如果你不使用弱引用並不會真的有什麼問題
我認為處處使用弱引用並不是一種最佳實踐。使用弱引用來修復記憶體洩漏的問題往往意味著缺乏合理的架構。
雖然文章中給出的例子修復了潛在的記憶體洩漏問題,但是也有其它的方法。我可以給出兩個耗時後臺任務中避免記憶體洩漏的例子。
避免AsyncTask記憶體洩漏的簡單例子:
Activity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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實現的簡單例子,我們仍然沒有使用弱引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
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(); } } |
注意如果我們沒有unsubscribe Subscription那麼仍然可能會出現記憶體洩漏。
最後我給出兩個Novoda的專案,它們是很好的學習資源。你可能猜到了,它們並沒有使用任何弱引用:)。
novoda/spikes
spikes – Where ideas & concepts are born & incubatedgithub.com
我認為一個很重要的守則是讓內部類為靜態的。尤其是它們要做耗時的後臺任務的時候。或者更好的方法是把這個類移到外面作為單獨的類。
用非靜態的內部類做耗時的後臺任務總是很糟糕的實踐,不光是在安卓中。