在onPause()中如何处理AsyncTask?

9

我在我的Activity中使用了一个AsyncTask,代码如下:

public class MyActivity {
    private AsyncTask mTask;

    private void doSomethingCool() {
        mTask = new AsyncTask(...);
        mTask.execute();
    }

    @Override
    protected void onPause() { 
        super.onPause();

        // How do I let the task keep running if just rotating?
        if (isFinishing() == false) {
            ... 
        }
    }
}

如果用户旋转设备,onPause() 将被调用,但我不想仅因此取消任务。我知道有一种方法可以告诉系统不要在旋转时销毁我的活动,但这对于这个问题是否推荐?我应该将 AsyncTask 放在一个静态全局类中,以便不绑定到 Activity 吗?
谢谢
4个回答

5
这是对Daniel答案的补充,但比我可以在评论中放置的字符数更多。
往往情况下,当我使用AsyncTask时,我想要一个旋转的对话框,而处理它非常荒谬。您必须执行与Daniel链接主题中的解决方案非常相似的操作。
基本原则是,使Task对象显式引用其父对象。通过屏幕旋转保留Task对象(使用onRetainNonConfigurationInstance),然后在onCreate中,确保如果Task存在并且您来自屏幕旋转,则将Task的父Activity设置为新实例。在任务内部,请务必在显式父对象上调用所有Activity方法。
您可以在此处查看我在基本ListActivity上执行此操作的示例: http://github.com/klondike/android-campfire/blob/master/src/com/github/klondike/android/campfire/RoomList.java 我会做一件与该示例不同的事情,即将Task的大部分onPostExecute移动到Activity的方法中,仅出于代码整洁性的原因。

代码不再像以前那样运行了,但是如果有帮助的话,项目的代码已经移动到这里:https://github.com/konklone/campyre - Eric Mill

4
在深入研究AsyncTask和方向更改之前,让我先问一下 - 您是否需要将AsyncTask保存在变量中?很少有理由这样做,因为AsyncTask内置了回调,所以实际上您不需要保留AsyncTask(不要打电话给他,他会打电话给您)。此外,您的AsyncTask应该在方向更改期间继续运行 - 毕竟它在另一个线程中。
我唯一需要保留AsyncTask的时间是修复错误时,当您尝试在AsyncTask正在运行时显示对话框时会出现错误。有一个解决方法,但它非常恶劣。如果这是您遇到的特定问题,则有很多讨论

6
好的,在这种情况下,我不需要保留它。 我正在任务中通过网络运行登录功能。 因此,我只需要在完成时得到通知。 但是,如果用户销毁了活动,然后任务完成,我不明白会发生什么,它会“回调”什么? 它是否仍会尝试触摸现在已被销毁的活动? - Mark
1
我认为你还没有完全理解这个问题。一个人不需要持有任务的引用,但是任务必须持有(通常是隐式的)对活动的引用。现在,如果您不希望您的活动始终保留其状态,则可能会发生配置更改将分离该活动并替换为新活动的情况。现在,当任务“回调”您准备好的数据时,它正在调用旧的活动实例,并且任何尝试更新UI的操作都会导致崩溃。那么,应该如何解决这个问题?保留状态,onPause时取消任务或其他方法? - Timo

1
如果你真的想一直运行它: 我在我的继承自AsyncTask的类中使用了单例模式,并在onResume中调用它:
@Override
protected void onResume() {
super.onResume();
// connection observer
if (!(AsyncTaskConnectionObserver.getInstance().getStatus() == AsyncTask.Status.RUNNING)) {
    AsyncTaskConnectionObserver.getInstance().execute();
}
}

在onDestroy中,我什么也不做(是的,在旋转时会调用它!),而这个任务确实会一直运行下去...

单例模式看起来像这样(只有结构,但我认为你会明白):

public class AsyncTaskConnectionObserver extends AsyncTask<Void, Void, Void> {

private AsyncTaskConnectionObserver(){
super();
}
/**
 * SingletonHolder is loaded on the first execution of
 * Singleton.getInstance() or the first access to SingletonHolder.INSTANCE,
 * not before.
 */
private static class SingletonHolder {
    public static final AsyncTaskConnectionObserver INSTANCE = new AsyncTaskConnectionObserver();
}

public static AsyncTaskConnectionObserver getInstance() {
    return SingletonHolder.INSTANCE;
}

}

1

点击这里查看一个很棒的帖子,它发布在android-developers邮件列表中,提供了一些关于如何处理屏幕转换或接收来电时运行AsyncTask的好信息。

这篇文章是由Mark Murphy从http://commonsware.com/撰写的。

他还包括了一个链接,指向他的一个项目,该项目使用总线系统来处理后台线程。https://github.com/commonsguy/cwac-bus/tree

我最终实现了类似于这篇文章中的东西,并且在我的应用程序中运行得非常好!


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