你并不一定要用弱引用来避免内存泄漏

FrancesMess 9年前
   <p style="text-align:center"><img src="https://simg.open-open.com/show/1220c60f96527cb5fee2fdc7af008961.jpg"></p>    <p>我的一个同事最近提到他们看的一个演讲,其中讲到:</p>    <p>如果你是一个安卓开发者却不使用弱引用,那么你就有麻烦了。</p>    <p>我个人认为这不仅是一种错误观点,而且相当误导人。WeakReference(弱引用)应该是修复内存泄漏的最后手段。</p>    <p>然后今天,我看到了 Enrique López Mañas 发布在Google Developers Experts专栏的一篇文章。</p>    <p><a href="/misc/goto?guid=4959729358960450486" rel="nofollow,noindex">Finally understanding how references work in Android and Java</a></p>    <p><a href="/misc/goto?guid=4959729358960450486" rel="nofollow,noindex">A few weeks ago I attended Mobiconf, one of the best conferences for Mobile Developers I had the pleasure to attend in…medium.com</a></p>    <p>这是一篇总结Java引用的好文章。</p>    <p>这篇文章并没有说必须使用弱引用,但是也没有给出替代的方案。我觉得我必须给出其它的方法来阐明弱引用并不是必须使用。</p>    <p>如果你不使用弱引用并不会真的有什么问题</p>    <p>我认为处处使用弱引用并不是一种最佳实践。使用弱引用来修复内存泄漏的问题往往意味着缺乏合理的架构。</p>    <p>虽然文章中给出的例子修复了潜在的内存泄漏问题,但是也有其它的方法。我可以给出两个耗时后台任务中避免内存泄漏的例子。</p>    <p>避免AsyncTask内存泄漏的简单例子:</p>    <p>Activity:</p>    <pre>  <code class="language-java">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        }      };    }  }</code></pre>    <p>这里是AsyncTask:</p>    <pre>  <code class="language-java">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);    }  }</code></pre>    <p>当然这个例子非常基础,但是我认为作为另一种解决方案的演示来说足够了。</p>    <p>这里是另一个使用RxJava实现的简单例子,我们仍然没有使用弱引用。</p>    <pre>  <code class="language-java">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();    }    }</code></pre>    <p>注意如果我们没有unsubscribe Subscription那么仍然可能会出现内存泄漏。</p>    <p>最后我给出两个Novoda的项目,它们是很好的学习资源。你可能猜到了,它们并没有使用任何弱引用:)。</p>    <p><a href="/misc/goto?guid=4959729359056058106" rel="nofollow,noindex">novoda/bonfire-firebase-sample</a></p>    <p><a href="/misc/goto?guid=4959729359056058106" rel="nofollow,noindex">bonfire-firebase-sample - An app to discuss your favourite emojis. This is a sample app built with Firebase.github.com</a></p>    <p><a href="/misc/goto?guid=4959729359147707565" rel="nofollow,noindex">novoda/spikes</a></p>    <p><a href="/misc/goto?guid=4959729359147707565" rel="nofollow,noindex">spikes - Where ideas & concepts are born & incubatedgithub.com</a></p>    <p>我认为一个很重要的守则是让内部类为静态的。尤其是它们要做耗时的后台任务的时候。或者更好的方法是把这个类移到外面作为单独的类。</p>    <p>用非静态的内部类做耗时的后台任务总是很糟糕的实践,不光是在安卓中。</p>    <p> </p>    <p>来自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/1213/6850.html</p>    <p> </p>