Android - RxJava vs AsyncTask防止getActivity()内存泄漏

时间:2015-02-04 15:51:41

标签: android memory-leaks android-asynctask rx-java

在Android中如何使用RxJava(或RxAndroid等)代替AsyncTask有助于防止上下文泄漏?在AsyncTask中,如果您执行它并且用户离开应用程序,那么活动上下文可以为null并且应用程序可能会崩溃。我听说RxJava可以在进行线程时帮助防止这种类型的崩溃。我还听说它可以做更好的错误处理,然后是AsyncTask的doInBackground方法(它会严重处理错误)。大多数时候我只是在doInBackground中返回null(例如),如果有任何失败,但我已经读过RxJava可以返回确切的错误而不是泄漏。谁能举个例子?

如果用户在尝试向UI报告结果时离开应用,则会在AsyncTask中发生崩溃的小演示:

     @SuppressWarnings("unused")
private class GetTask extends AsyncTask<Void, Void, Void> {         

    @Override
    protected void onPostExecute(String result) {         
        pd = new ProgressDialog(getActivity().getApplicationContext());//can crash right here
        pd.setTitle("Grabbing Track!");
        pd.setMessage("Please wait...");
        pd.setCancelable(false);
        pd.setIndeterminate(true);
        pd.show();
    }}

这是一个doInBackground方法调用,它不会发出有用的错误:

@Override 
protected String doInBackground(String... params) {
    String myIntAsString = 1/0 + ""; //this should give an error (how do we report it to the caller??
                                  //or if we are parsing json and it fails, how do we report it to the caller cleanly. Can RxJava help?
}

2 个答案:

答案 0 :(得分:9)

我认为关于RxJava的好处是,如果你有一堆任务,你可以把它们放在一个顺序中,这样你就知道什么时候完成而下一个即将开始。在AsyncTask中如果你有多个运行,你不能保证哪个任务将首先完成,然后你必须做很多错误检查,如果你关心订单。所以RxJava允许你对调用进行排序。

关于内存泄漏,我们可以将AsyncTask作为活动的内部类。现在,因为当活动被破坏时它与活动相关联,上下文仍然悬而未开,并且不会被垃圾收集,这就是内存泄漏部分。

这是RxJava可以提供帮助的地方。如果发生任何错误,那么我们可以调用订阅者onError方法。订阅者可以这样:

    public Observable<JsonObject> get_A_NetworkCall() {
    // Do your network call...but return an observable when done
}

Subscription subscription = get_A_NetworkCall()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<jsonResponse>() {

        @Override
        public void onCompleted() {
             // Update UI
        }

        @Override
        public void onError() {
             // show error on UI
        }

        @Override
        public void onNext(JsonObject response) {
             // Handle result of jsonResponse 
        }
});

或类似的东西 - 这是伪造的。关键是你可以更干净地报告错误并在一行中切换线程。在这里,我们报告了机器人主线程,但在新线程上进行了工作。在我们的活动onDestroy方法完成之后,我们可以简单地取消订阅observable并将其杀死并防止我们遇到的任何内存泄漏与AsyncTask。这对我来说应该是任何asyncTasks的替代品。

答案 1 :(得分:5)

我使用了两件事的组合。首先,RxAndroid非常有用: https://github.com/ReactiveX/RxAndroid

您可以在其上使用AppObservable.bindActivity绑定一个observable,以便在主线程上观察其输出,如果计划销毁该活动,则不会转发消息。您仍然需要管理暂停/恢复生命周期。为此,我使用这样的复合订阅(pseudojava即将发布):

public class MyActivity extends Activity {
  private final CompositeSubscription subscriptions = new CompositeSubscription();

  @Override
  public void onResume() {
    super.onResume();
    subscriptions.add(AppObservable.bindActivity(this, myObservable)
        .subscribe());
    subscriptions.add(AppObservable.bindActivity(this, myOtherObservable)
        .subscribe());
  }

  @Override
  public void onPause() {
    subscriptions.clear();
    super.onPause();
  }

}

显然,如果您想对数据执行某些操作,您希望在subscribe中执行更多操作,但重要的是收集返回的Subscription实例并将其添加到{ {1}}。当它清除它们时,它也会取消订阅它们。

使用这两个奇怪的技巧&#39;当事件处于不工作状态时,应该让事情不再回到活动状态。