Android - RxJava vs AsyncTask 以防止 getActivity() 内存泄漏
Android - RxJava vs AsyncTask to prevent getActivity() memory leak
在 Android 中使用 RxJava(或 RxAndroid 等)而不是 AsyncTask 如何帮助防止上下文泄漏?在 AsyncTask 中,如果您执行它并且用户离开了应用程序,那么 activity 上下文可能为空并且应用程序可能会崩溃。我听说 RxJava 在执行线程时可以帮助防止这种类型的崩溃。我还听说它可以比 AsyncTask 的 doInBackground 方法(它处理错误很糟糕)做更好的错误处理。大多数时候,如果有任何失败,我只是在 doInBackground 中 return null(例如),但我读过 RxJava 可以 return 确切的错误而不是泄漏。谁能举个例子?
这是一个小演示,如果用户在尝试向 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?
}
我认为 RxJava 的好处在于,如果你有一堆任务,你可以将它们按顺序排列,这样你就知道一个何时完成,下一个何时开始。在 AsyncTask 中,如果您有多个 运行,则无法保证哪个任务将首先完成,如果您关心顺序,则必须进行大量错误检查。所以 RxJava 允许你对调用进行排序。
关于内存泄漏,我们可以将 AsyncTask 作为 activity 的内部 class。现在,由于它与 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
}
});
或类似的东西 - 这是 psuedocode 。关键是您可以更干净地报告错误并在一行中切换线程。在这里,我们在 androids 主线程上进行报告,但在新线程上进行工作。在我们的活动 onDestroy 方法完成后,我们可以简单地取消订阅 observable 并杀死它并防止我们遇到 AsyncTask 的任何内存泄漏。这对我来说应该是任何 asyncTasks 的替代品。
我结合使用了两种东西。首先,RxAndroid
真的很有帮助:
https://github.com/ReactiveX/RxAndroid
您可以在其上使用 AppObservable.bindActivity
绑定一个可观察对象,以便在主线程上观察其输出,如果计划销毁 activity,则不会转发消息。不过,您仍然需要管理 pause/resume 生命周期。为此,我使用这样的复合订阅(即将出现伪java):
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
。当它清除它们时,它也会取消订阅它们。
使用这些 'two weird tricks' 应该可以防止在 Activity 处于无效状态时返回到 Activity。
在 Android 中使用 RxJava(或 RxAndroid 等)而不是 AsyncTask 如何帮助防止上下文泄漏?在 AsyncTask 中,如果您执行它并且用户离开了应用程序,那么 activity 上下文可能为空并且应用程序可能会崩溃。我听说 RxJava 在执行线程时可以帮助防止这种类型的崩溃。我还听说它可以比 AsyncTask 的 doInBackground 方法(它处理错误很糟糕)做更好的错误处理。大多数时候,如果有任何失败,我只是在 doInBackground 中 return null(例如),但我读过 RxJava 可以 return 确切的错误而不是泄漏。谁能举个例子?
这是一个小演示,如果用户在尝试向 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?
}
我认为 RxJava 的好处在于,如果你有一堆任务,你可以将它们按顺序排列,这样你就知道一个何时完成,下一个何时开始。在 AsyncTask 中,如果您有多个 运行,则无法保证哪个任务将首先完成,如果您关心顺序,则必须进行大量错误检查。所以 RxJava 允许你对调用进行排序。
关于内存泄漏,我们可以将 AsyncTask 作为 activity 的内部 class。现在,由于它与 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
}
});
或类似的东西 - 这是 psuedocode 。关键是您可以更干净地报告错误并在一行中切换线程。在这里,我们在 androids 主线程上进行报告,但在新线程上进行工作。在我们的活动 onDestroy 方法完成后,我们可以简单地取消订阅 observable 并杀死它并防止我们遇到 AsyncTask 的任何内存泄漏。这对我来说应该是任何 asyncTasks 的替代品。
我结合使用了两种东西。首先,RxAndroid
真的很有帮助:
https://github.com/ReactiveX/RxAndroid
您可以在其上使用 AppObservable.bindActivity
绑定一个可观察对象,以便在主线程上观察其输出,如果计划销毁 activity,则不会转发消息。不过,您仍然需要管理 pause/resume 生命周期。为此,我使用这样的复合订阅(即将出现伪java):
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
。当它清除它们时,它也会取消订阅它们。
使用这些 'two weird tricks' 应该可以防止在 Activity 处于无效状态时返回到 Activity。