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
提供给您的:一个长时间后台操作的容器,可以在活动消失后存活下来,并让安卓知道还有什么东西在附近。