简体   繁体   English

aSyncTask死锁第二个aSyncTask

[英]aSyncTask Deadlocking Second aSyncTask

I encountered a problem today involving aSyncTasks in my Android project and after some research have found the answer and, as no-one I had spoken to had ever realised, so I thought I'd share with the SO community in case anyone finds it to be of any use. 我今天在我的Android项目中遇到了一个涉及aSyncTasks的问题,经过一些研究找到了答案,并且正如我曾经说过的那个人没有意识到的那样,所以我想我会与SO社区分享以防万一有人发现它有用。

A Brief overview of my problem: 我的问题简要概述:

I have a UI activity class to download packages of multiple files when the install button is clicked. 我有一个UI活动类,可以在单击安装按钮时下载多个文件的包。 The file "bundles" are split into up to four separate downloads and the "Group" information is stored in a custom class along with other information for the files. 文件“捆绑”分为最多四个单独的下载,“组”信息与其他文件信息一起存储在自定义类中。 When the download button is clicked, (up to) four jobs are queued with the android DownloadManager via a utility, DownloadUtilities. 单击下载按钮时,(最多)四个作业通过实用程序DownloadUtilities与android DownloadManager排队。

When a "group" download is enqueued by DownloadUtilities, the DownloadManager download references are stored inside the "group" custom class for later use. 当DownloadUtilities将“组”下载排队时,DownloadManager下载引用存储在“组”自定义类中以供以后使用。

The Download Utilities class features a BroadcastReceiver to acknowledge the files and update the download references to 0 for each element of the group as they finish downloading to show that they are finished. Download Utilities类具有BroadcastReceiver,用于确认文件,并在组完成下载时将组的每个元素的下载引用更新为0,以表明它们已完成。

Once all files in a group are finished downloading, they can be processed. 一旦组中的所有文件都完成下载,就可以处理它们。 This is done by an aSyncTask triggered by the DownloadReceiver. 这是由DownloadReceiver触发的aSyncTask完成的。

This in turn, triggers a broadcast to notify the UI activity that the requested download has been finished so the UI can be updated accordingly. 这反过来触发广播以通知UI活动所请求的下载已经完成,因此可以相应地更新UI。

Everything worked great until this point, however, I found an issue when I tried to add a progress bar to show the progress of the "group" 到目前为止,一切都很顺利,然而,当我尝试添加进度条以显示“组”的进度时,我发现了一个问题

To update the ProgressBar, I created a new aSyncTask which could query the download manager to calculate the total size of the downloading files, and then poll once a second to update the ProgressBar to show the current download progress. 为了更新ProgressBar,我创建了一个新的aSyncTask,它可以查询下载管理器以计算下载文件的总大小,然后每秒轮询一次以更新ProgressBar以显示当前的下载进度。

The doInBackground() thread consists of the following pseudocode: 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

The problem I found was that the system would deadlock. 我发现的问题是系统会死锁。 Logcat would should the download receiver being told a file had finished downloading by the DownloadManager, and that the ProcessDownload aSyncTask onPreExecute() was running, but the doInBackGround was never running. Logcat应该告诉下载接收器文件已经由DownloadManager完成下载,并且ProcessDownload aSyncTask onPreExecute()正在运行,但doInBackGround从未运行。

In the meantime, the download monitor was constantly looping in the doInBackground() because the condition of the while loop was never being deasserted, because the deassertion is done in the ProcessDownload doInBackground() thread. 与此同时,下载监视器不断在doInBackground()中循环,因为while循环的条件永远不会被置为无效,因为取消断言是在ProcessDownload doInBackground()线程中完成的。

It became apparent that the aSyncTask doInBackground() methods were mutually exclusive and so causing a deadlock but I had no idea why. 很明显,aSyncTask doInBackground()方法是互斥的,因此导致死锁,但我不知道为什么。 I had never knowingly structured my code in such a way in the past that this posed an issue... 我过去从未故意以这种方式构建我的代码,这构成了一个问题......

My understanding was that aSyncTasks offered a developer friendly way to multithread your code but it seems that this is not the case... 我的理解是aSyncTasks提供了一种开发人员友好的方式来多线程你的代码,但似乎并非如此......

So I spent several hours trying to work out what may have been causing the issue and came to the conclusion that based on my understanding of what aSyncTasks were, there was no reason my code shouldn't work... So I took to the internet to trawl documentation and eventually found the answer. 所以我花了几个小时试图解决可能导致问题的原因并得出结论,基于我对aSyncTasks的理解,我的代码没有理由不起作用......所以我上网了拖网文件,最终找到了答案。

"Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution. “从HONEYCOMB开始,任务在单个线程上执行,以避免由并行执行引起的常见应用程序错误。

If you truly want parallel execution, you can invoke executeOnExecutor(java.util.concurrent.Executor, Object[]) withTHREAD_POOL_EXECUTOR." 如果您真的想要并行执行,可以使用THREAD_POOL_EXECUTOR调用executeOnExecutor(java.util.concurrent.Executor,Object [])。“

It seems that my thinking did USED to be the way, however, as of Honeycomb, it was no longer. 似乎我的想法确实是用途的,然而,就像Honeycomb一样,它已经不再存在了。 aSyncTasks DO offload code from the UI thread, however, it offloads it onto a single thread with multiple aSyncTask doInBackground() methods being executed sequentially. aSyncTasks DO卸载来自UI线程的代码,但是,它将其卸载到单个线程上,并且顺序执行多个aSyncTask doInBackground()方法。

So I went back and changed my code to use good 'ol Java Threads and lo and behold, my code works! 所以我回去改变了我的代码,使用了很好的'ol Java Threads',看看我的代码是有效的!

Anyone thinking of using dependent code, it's worth thinking carefully and looking into aSyncTasks to be sure you understand its behaviour. 任何想要使用依赖代码的人,都值得仔细思考并查看aSyncTasks以确保您了解其行为。 They're a great tool I've used a lot in the past, but with more 'advanced?' 它们是我过去经常使用的一个很好的工具,但更先进? stuff, it may be better to go back to basics. 东西,回到基础可能会更好。

Hopefully this will be of use to someone, I have wasted a lot of time on this because of a simple misunderstanding of the behaviour of an aSyncTask -.- 希望这对某人有用,我浪费了很多时间,因为对aSyncTask的行为有一个简单的误解 - .-

Source that gave me the answer 来源给了我答案

EDIT: 编辑:

Props to Krylez for pointing me to http://commonsware.com/blog/2012/04/20/asynctask-threading-regression-confirmed.html which also features a really eloquent way of maintaining compatibility with both pre and post Honeycomb devices. 向Krylez道具的道具指向http://commonsware.com/blog/2012/04/20/asynctask-threading-regression-confirmed.html ,其中还有一种非常雄辩的方式来保持与蜂窝前后设备的兼容性。 All that is necessary is to modify the aSyncTask call 所有必要的是修改aSyncTask调用

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

which reverts Honeycomb+ behavior to how it used to be 它将Honeycomb +行为恢复到过去的状态

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM