你并不一定要用弱引用來避免內存泄漏

FrancesMess 7年前發布 | 7K 次閱讀 安卓開發 Android開發 移動開發

我的一個同事最近提到他們看的一個演講,其中講到:

如果你是一個安卓開發者卻不使用弱引用,那么你就有麻煩了。

我個人認為這不僅是一種錯誤觀點,而且相當誤導人。WeakReference(弱引用)應該是修復內存泄漏的最后手段。

然后今天,我看到了 Enrique López Ma?as 發布在Google Developers Experts專欄的一篇文章。

Finally understanding how references work in Android and Java

A few weeks ago I attended Mobiconf, one of the best conferences for Mobile Developers I had the pleasure to attend in…medium.com

這是一篇總結Java引用的好文章。

這篇文章并沒有說必須使用弱引用,但是也沒有給出替代的方案。我覺得我必須給出其它的方法來闡明弱引用并不是必須使用。

如果你不使用弱引用并不會真的有什么問題

我認為處處使用弱引用并不是一種最佳實踐。使用弱引用來修復內存泄漏的問題往往意味著缺乏合理的架構。

雖然文章中給出的例子修復了潛在的內存泄漏問題,但是也有其它的方法。我可以給出兩個耗時后臺任務中避免內存泄漏的例子。

避免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實現的簡單例子,我們仍然沒有使用弱引用。

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/bonfire-firebase-sample

bonfire-firebase-sample - An app to discuss your favourite emojis. This is a sample app built with Firebase.github.com

novoda/spikes

spikes - Where ideas & concepts are born & incubatedgithub.com

我認為一個很重要的守則是讓內部類為靜態的。尤其是它們要做耗時的后臺任務的時候。或者更好的方法是把這個類移到外面作為單獨的類。

用非靜態的內部類做耗時的后臺任務總是很糟糕的實踐,不光是在安卓中。

 

來自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/1213/6850.html

 

 本文由用戶 FrancesMess 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!