aSyncTask死锁第二个aSyncTask

时间:2013-07-24 21:16:57

标签: java android android-asynctask deadlock

我今天在Android项目中遇到了一个涉及aSyncTasks的问题,并且经过一些研究找到了答案,而且我曾经说过没有人能够实现过,所以我想我会与SO社区分享以防任何人发现它有用。

我的问题简要概述:

我有一个UI活动类,可以在单击安装按钮时下载多个文件的包。文件“捆绑”分为最多四个单独的下载,“组”信息与其他文件信息一起存储在自定义类中。单击下载按钮时,(最多)四个作业通过实用程序DownloadUtilities与android DownloadManager排队。

当DownloadUtilities将“组”下载排队时,DownloadManager下载引用存储在“组”自定义类中以供以后使用。

Download Utilities类具有BroadcastReceiver,用于确认文件,并在组完成下载后将组的每个元素的下载引用更新为0,以表明它们已完成。

一旦组中的所有文件都下载完毕,就可以处理它们。这是由DownloadReceiver触发的aSyncTask完成的。

这反过来会触发广播以通知UI活动所请求的下载已经完成,因此可以相应地更新UI。

在此之前一切都很顺利,然而,当我尝试添加进度条以显示“组”的进度时,我发现了一个问题

为了更新ProgressBar,我创建了一个新的aSyncTask,它可以查询下载管理器以计算下载文件的总大小,然后每秒轮询一次以更新ProgressBar以显示当前的下载进度。

doInBackground()线程由以下伪代码组成:

Check if file1 is being downloaded, if it is, query the download manager for the total file size and add it to total
Same for files2-4

While the download references are not all 0:
If file 1 is still downloading, get file1 download total
Same for file2-4
Update progress to sum of downloaded bytes/total

我发现问题是系统会死锁。 Logcat会告诉下载接收器文件是否已经由DownloadManager完成下载,并且ProcessDownload aSyncTask onPreExecute()正在运行,但doInBackGround从未运行。

与此同时,下载监视器在doInBackground()中不断循环,因为while循环的条件永远不会被置为无效,因为取消断言是在ProcessDownload doInBackground()线程中完成的。

很明显,aSyncTask doInBackground()方法是互斥的,因此导致死锁,但我不知道为什么。我过去从来没有故意以这样的方式构建我的代码,这构成了一个问题......

我的理解是aSyncTasks提供了一种开发人员友好的方式来多线程化您的代码,但似乎情况并非如此......

1 个答案:

答案 0 :(得分:2)

所以我花了几个小时试图解决可能导致问题的原因,并得出结论,根据我对aSyncTasks的理解,没有理由我的代码不能工作......所以我拿了到互联网上搜索文档并最终找到答案。

  

“从HONEYCOMB开始,任务在单个线程上执行   避免因并行执行而导致的常见应用程序错误。

     

如果您真的想要并行执行,可以调用   executeOnExecutor(java.util.concurrent.Executor,Object [])   withTHREAD_POOL_EXECUTOR“。

似乎我的想法确实是用途的,然而,就像Honeycomb一样,它已经不再存在了。 aSyncTasks DO从UI线程卸载代码,但是,它将它卸载到单个线程上,并且顺序执行多个aSyncTask doInBackground()方法。

所以我回去更改了我的代码,使用了很好的'ol Java Threads',看看我的代码是否正常工作!

任何想要使用依赖代码的人,都值得仔细思考并查看aSyncTasks以确保您了解其行为。它们是我过去经常使用的一个很好的工具,但更先进?事情,回到基础可能会更好。

希望这对某人有用,我浪费了很多时间,因为对aSyncTask的行为有一个简单的误解-.-

Source that gave me the answer

编辑:

向Krylez道具指向我http://commonsware.com/blog/2012/04/20/asynctask-threading-regression-confirmed.html,其中还有一种非常雄辩的方式来保持与蜂窝前后设备的兼容性。所有必要的是修改aSyncTask调用

if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) {
  myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
else {
  myTask.execute();
}

将Honeycomb +行为恢复为以前的行为