今日、私の Android プロジェクトで aSyncTasks に関連する問題が発生しました。いくつかの調査で答えが見つかりました。私が話した人は誰も気づいていなかったので、誰かがそれを見つけた場合に備えて、SO コミュニティと共有したいと思いました。何の役にも立たない。
私の問題の簡単な概要:
インストール ボタンがクリックされたときに複数のファイルのパッケージをダウンロードする UI アクティビティ クラスがあります。ファイル「バンドル」は最大 4 つの個別のダウンロードに分割され、「グループ」情報はファイルの他の情報とともにカスタム クラスに保存されます。ダウンロード ボタンをクリックすると、(最大) 4 つのジョブが、ユーティリティ DownloadUtilities を介して android DownloadManager でキューに入れられます。
「グループ」ダウンロードが DownloadUtilities によってキューに入れられると、DownloadManager ダウンロード参照が「グループ」カスタム クラス内に保存され、後で使用できるようになります。
Download Utilities クラスには BroadcastReceiver があり、ファイルの確認を行い、ダウンロードが終了したことを示すためにグループの各要素のダウンロード参照を 0 に更新します。
グループ内のすべてのファイルのダウンロードが完了すると、それらを処理できます。これは、DownloadReceiver によってトリガーされる aSyncTask によって行われます。
これにより、要求されたダウンロードが完了したことを UI アクティビティに通知するブロードキャストがトリガーされ、それに応じて UI を更新できるようになります。
この時点まではすべて問題なく機能していましたが、「グループ」の進行状況を表示する進行状況バーを追加しようとしたときに問題が見つかりました。
ProgressBar を更新するために、ダウンロード マネージャーにクエリを実行してダウンロード ファイルの合計サイズを計算し、1 秒に 1 回ポーリングして ProgressBar を更新し、現在のダウンロードの進行状況を表示できる新しい aSyncTask を作成しました。
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 はコードをマルチスレッド化するための開発者に優しい方法を提供していましたが、そうではないようです...