Android AsyncTask在方向更改时阻止用户界面

Android AsyncTask在方向更改时阻止用户界面,android,orientation,rotation,android-asynctask,Android,Orientation,Rotation,Android Asynctask,我有一个很奇怪的问题。我有一个AsyncTask,当我旋转手机时,它会阻止UI线程 首先,让我声明,我对我的活动在轮换时被销毁和重新创建感到满意。我将AsyncTask保存在onretainonconfigurationinstance()中,在onDestroy()中将活动与其分离,并使用getLastNonConfigurationInstance()在onCreate()中重新附加到它 只要AsyncTask没有做繁重的工作,这一切都很好。例如,要调试我的问题,我有这样一个方法,它完全按照

我有一个很奇怪的问题。我有一个
AsyncTask
,当我旋转手机时,它会阻止UI线程

首先,让我声明,我对我的
活动在轮换时被销毁和重新创建感到满意。我将
AsyncTask
保存在
onretainonconfigurationinstance()
中,在
onDestroy()
中将活动与其分离,并使用
getLastNonConfigurationInstance()
onCreate()
中重新附加到它

只要
AsyncTask
没有做繁重的工作,这一切都很好。例如,要调试我的问题,我有这样一个方法,它完全按照预期工作,没有UI阻塞:

@Override
protected Boolean doInBackground(Void... params) {
    boolean success = false;
    final DbAdapter dbAdapter = dbService.getAdapter();

    try {
        // pretend to do some complicated work
        Thread.sleep(20000);
        success = true;
    } catch (Exception e) {
        e.printStackTrace();
    }

    return success;
}
但是,如果我将其更改为在后台执行一些实际工作,则在调用
onPause()
开始旋转和稍后在新方向调用
onResume()
之间会有很长的延迟。此延迟为数十秒,在此期间,UI处于不一致状态(旧布局被剪切到新方向),并且似乎旋转在
AsyncTask
上受阻。唯一的更改是try块内的两行:

@Override
protected Boolean doInBackground(Void... params) {
    boolean success = false;
    final DbAdapter dbAdapter = dbService.getAdapter();

    try {
        // actually do some complicated work
        XmlParser parser = new XmlParser(context, dbAdapter);
        success = parser.parse(source);
    } catch (Exception e) {
        e.printStackTrace();
    }

    return success;
}
上下文
是传递给
异步任务
的构造函数的全局应用程序上下文,因此我不认为我意外地保留了对传出的
活动
的引用


还有什么可能出错?

可能您的活动也在尝试使用
dbAdapter
,并且您正在进行适当的同步,以防止两个线程同时使用
dbAdapter

可能是您的活动试图在主应用程序线程上加载文件系统的内容,而您的数据库操作导致了太多的争用。在硬件上,YAFFS2对于I/O操作来说是有效的单线程

您可以使用Traceview尝试获取有关占用您时间的内容的更多信息,也可以在Android 2.2及更高版本上使用
StrictMode
,查看您的活动可能试图在主应用程序线程上执行文件I/O的位置


另外,如果您的
AsyncTask
正在将XML转换为数据库条目,那么这可能是更好地使用
IntentService
而不是
AsyncTask
,可能您的活动也在尝试使用
dbAdapter
,并且您可以进行适当的同步,以防止两个线程同时使用
dbAdapter

可能是您的活动试图在主应用程序线程上加载文件系统的内容,而您的数据库操作导致了太多的争用。在硬件上,YAFFS2对于I/O操作来说是有效的单线程

您可以使用Traceview尝试获取有关占用您时间的内容的更多信息,也可以在Android 2.2及更高版本上使用
StrictMode
,查看您的活动可能试图在主应用程序线程上执行文件I/O的位置


另外,如果您的
AsyncTask
正在将XML转换为数据库条目,那么这可能是更好地使用
IntentService
而不是
AsyncTask

,感谢您为我指明了正确的方向。它是数据库争用;长时间运行的数据库操作包装在事务中。如果我禁用事务,它可以正常工作(但需要10倍的时间)。有趣的是,争论不在可见的活动中;我的活动是Tabhost中的几个活动之一,它是等待数据库解除阻止的其他活动之一(在旋转时不可见)。关于您的IntentService建议。。。据我所知,将结果反馈给UI比较困难,例如关闭进度对话框。你能给我解释一下为什么IntentService可能比AsyncTask好吗?@Graham Borland:在某些情况下,它可能并不比
IntentService
好。您没有在问题中规定需要更新UI。请记住,即使在用户按下返回键时泄漏了
AsyncTask
,后台工作也可能无法完成,因为Android可能会在您完成之前终止该进程,因为它可能认为没有任何其他运行方式可以证明该进程是合理的。这就是一个
IntentService
给你的:一个长时间后台操作的容器,可以在活动结束后存活下来,并让安卓知道还有一些东西在附近。谢谢你为我指明了正确的方向。它是数据库争用;长时间运行的数据库操作包装在事务中。如果我禁用事务,它可以正常工作(但需要10倍的时间)。有趣的是,争论不在可见的活动中;我的活动是Tabhost中的几个活动之一,它是等待数据库解除阻止的其他活动之一(在旋转时不可见)。关于您的IntentService建议。。。据我所知,将结果反馈给UI比较困难,例如关闭进度对话框。你能给我解释一下为什么IntentService可能比AsyncTask好吗?@Graham Borland:在某些情况下,它可能并不比
IntentService
好。您没有在问题中规定需要更新UI。请记住,即使在用户按下返回键时泄漏了
AsyncTask
,后台工作也可能无法完成,因为Android可能会在您完成之前终止该进程,因为它可能认为没有任何其他运行方式可以证明该进程是合理的。这就是
IntentService
提供给您的:一个长时间后台操作的容器,可以在活动消失后存活下来,并让安卓知道还有什么东西在附近。