如何最佳实践地使用AsyncTask来检查Activity是否仍在运行

4

当AsyncTask完成后,我通常会执行以下操作之一:

  1. 在活动中定义一个回调对象/接口并将其传递给My AsyncTask子类构造函数,然后调用回调对象/接口上的方法。
  2. 为AsyncTask提供Handler,并在任务完成时调用myHandler.sendMessage()。

我的问题是,在AsyncTask完成后,什么被认为是最佳实践。如果用户在任务处理过程中按下主页按钮,则该活动不再处于前台。当应用程序尝试进行UI操作以响应任务完成时,操作系统会抛出WindowManager$BadTokenException异常。

我当然可以使用BadTokenException的catch语句来包围我的UI代码。但这似乎有些hacky。是否有任何方法可以判断活动是否在前台?


从您收到的错误信息来看,似乎您正在使用错误的上下文,请检查在必要时是否传递了有效的上下文。 - Lalit Poptani
@suri_sahani 你能具体说明一下通过传递有效的上下文是什么意思吗?从哪里传递到哪里?我正在将Activity作为上下文传递给我的AsyncTask子类构造函数。 - Glenn Bech
可能是Android AsyncTasks如何检查活动是否仍在运行的重复问题。 - Audrius Meškauskas
4个回答

2
也许我的答案会让你不太满意,但是我认为AsyncTask存在问题(就像这个原因一样)。
编辑:我的初始答案建议使用IntentService并广播结果。这和给自己寄信一样低效。
你可以使用AsyncTaskLoader来解决AsyncTask的问题,但是AsyncTaskLoader的API也很不完美。特别是,您必须确保loader id是唯一的,并且要知道结果是基于id缓存的,而不是基于参数缓存的。此外,异常的传播与AsyncTask一样有问题。
更现代和更安全的方法是使用Guava future

可以仅取消AsyncTask,而且大致上很清楚何时(在onDestroy中)。这个问题提供了更好的答案。IntentService非常容易使用,但如果您还需要返回答案,则使用AsyncTask的代码要少得多。 - Audrius Meškauskas
那是一个旧答案...我已经更新了它。现在我的建议是使用ListenableFuture。 - rds

1

您可以检查活动是否处于活动状态。我通常将我的AsyncTask子类设置为静态(以避免内存泄漏),因此我传递了一个活动的引用(再次使用WeakReference进行包装,以避免内存泄漏)。

当onPostExecute正在执行时,我会在使用WeakReferences时进行必要的检查,并调用Activity.isFinishing()来检查活动是否正在被销毁,以避免在正在死亡的Activity上执行UI更改。


1

这意味着您正在使用一些不适当的上下文。要消除有关异常的疑虑,请参阅此链接。 坏令牌异常


这似乎是问题所在。即使Async任务不在前台,它也可以调用活动类中的方法。 - Glenn Bech

0
在onStart()中定义一个静态成员作为您活动的对象 -
private static MyActivity mActivity = null;
public void onStart() {
    mActivity = this;
}

public void onDestroy() {
    mActivity = null;
}

然后在您的AsyncTask方法中,可以这样做:

if (mActivity != null) {
    mActivity.doSomething();  //make sure to use static member
}

嗨。我不认为这会起作用,你试过了吗?当用户按下主页按钮时,活动的onDestroy不会被调用。 - Glenn Bech
当然,我经常这样做。虽然,通常我不在意他们是否回家了。在这种情况下,您应该添加另一个静态布尔成员,并在onPause()中更改它并重置onResume(),然后根据您的逻辑进行处理。 - Miguel Morales

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