2011-03-09 54 views
1

我有一个很奇怪的问题。我有一个AsyncTask,当我旋转手机时,它似乎阻止了UI线程。Android AsyncTask阻止UI方向变化

首先,让我说我很满意我的Activity被破坏并在轮换时重新创建。我将AsyncTask保存在onRetainNonConfigurationInstance()中,将它从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; 
} 

context是到AsyncTask的构造函数传递一个全球性的应用程序上下文,所以我不认为我无意中保留的一个参考传出Activity

还有什么可能会出错?

回答

1

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

可能是您的活动试图从主应用程序线程上的文件系统加载内容,并且您的数据库操作造成了太多争用。在硬件上,YAFFS2实际上是单线程的I/O操作。

您可以使用Traceview试图获取更多关于什么花费您的时间的信息,并且您可以在Android 2.2及更高版本上使用StrictMode来查看您的活动可能试图在主应用程序上执行文件I/O的位置线。

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

+0

感谢您指点我正确的方向。这是数据库争夺;长时间运行的数据库操作被包装在一个事务中。如果我禁用交易,它可以正常工作(但需要10倍的时间)。有趣的是,争用不在可见的活动中;我的Activity是Tabhost中的几个中的一个,它是等待数据库解除阻塞的其他活动(在轮换时不可见)之一。 – 2011-03-09 10:05:44

+0

关于你的IntentService建议......这是我的理解,很难将结果传回UI,例如关闭进度对话框。你能指点我一个很好的解释,为什么一个IntentService可能比一个AsyncTask更好? – 2011-03-09 10:10:55

+0

@Graham Borland:在某些情况下,它可能并不比“IntentService”更好。你没有规定在你的问题中需要更新UI。请记住,即使您在用户按下BACK时泄漏了'AsyncTask',后台工作可能无法完成,因为Android可能会在您完成之前终止该流程,因为它可能认为没有其他任何内容可以运行来证明保留处理周围。这就是'IntentService'给你的:一个长时间后台操作的容器,可以在活动消失之后幸免于难并让Android知道一些事情。 – CommonsWare 2011-03-09 13:07:41