Android - RxJava与AsyncTask相比,如何防止getActivity()内存泄漏?

7
使用RxJava(或RxAndroid等)替代Android中的AsyncTask如何帮助防止上下文泄漏?在AsyncTask中,如果在执行它时用户离开了应用程序,则活动上下文可能为空,并且应用程序可能会崩溃。我听说过在执行线程操作时,RxJava可以帮助避免这种类型的崩溃。我还听说它可以比AsyncTask的doInBackground方法(错误处理不好)做到更好的错误处理。大多数情况下,如果任何事情出现问题,我只返回null(例如),但我读到RxJava可以返回精确的错误而不会泄漏。有人能给个例子吗?
以下是使用AsyncTask时,如果用户在其试图向UI报告结果时离开应用程序,则应用程序将崩溃的小演示:
     @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?
}

有趣的是你问到这个,我刚刚读完了这篇文章:http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/ - Budius
2个回答

9
我认为RxJava的好处在于,如果你有一堆任务,你可以按顺序将它们放在一起,这样你就知道一个任务何时完成,下一个任务何时开始。在AsyncTask中,如果有多个任务同时运行,你无法保证哪个任务先完成,然后你需要进行大量的错误检查,以确保顺序正确。因此,RxJava允许你对调用进行排序。
关于内存泄漏,我们可以将AsyncTask作为activity的内部类。现在,由于它与activity绑定,当activity被销毁时,该上下文仍然存在,不会被垃圾回收,这就是内存泄漏的部分。
这就是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 
        }
});

或类似的东西 - 这是伪代码。重点是您可以更干净地报告错误并在一行中切换线程。在这里,我们正在 android 的主线程上报告,但在新线程中执行工作。在我们的 activities onDestroy 方法完成后,我们只需取消订阅可观察对象即可将其杀死,并防止我们在 AsyncTask 中遇到的任何内存泄漏。对我来说,这应该成为任何 asyncTasks 的替代品。


另外需要补充的是,在 onPause() 或 onDestroy() 中记得取消订阅,如下所示: SubscriberObj.unsubscribe(); - Elye

5
我使用两个工具相结合。首先,RxAndroid非常有帮助:https://github.com/ReactiveX/RxAndroid 你可以使用AppObservable.bindActivity将可观察对象绑定到主线程上进行观察,如果活动被调度销毁,消息将不会被转发。但是,你仍然需要管理暂停/恢复生命周期。为此,我使用如下的组合订阅(伪代码即将呈现):
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实例并将它们添加到CompositeSubscription中。当清除它们时,也会取消订阅。

使用这些“两个奇怪的技巧”应该防止在Activity处于非运行状态时出现问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接