私はこの問題を何ヶ月も調査し、さまざまな解決策を考え出しましたが、それらはすべて大規模なハックであるため、満足していません. 設計に欠陥のあるクラスがフレームワークに組み込まれ、誰もそれについて話していないとはまだ信じられないので、何かが欠けているに違いないと思います。
問題はAsyncTask
. ドキュメントによると、
「スレッドやハンドラーを操作することなく、バックグラウンド操作を実行し、UI スレッドで結果を公開できます。」
showDialog()
この例では、いくつかの例示的なメソッドが でどのように呼び出されるかを引き続き示しますonPostExecute()
。ただし、ダイアログを表示するには常に valid への参照が必要であり、 AsyncTaskはcontext object への強い参照を保持してはならないため、これは完全に不自然に思えます。Context
その理由は明らかです。タスクをトリガーしたアクティビティが破棄された場合はどうなるでしょうか。これは、画面を反転したなどの理由で、常に発生する可能性があります。タスクがそれを作成したコンテキストへの参照を保持する場合、役に立たないコンテキスト オブジェクトを保持しているだけでなく (ウィンドウは破棄され、 UI の操作はすべて例外で失敗します!)、メモリーリーク。
ここで私のロジックに欠陥がない限り、これは次のように解釈されます:onPostExecute()
コンテキストにアクセスできない場合、UI スレッドでこのメソッドを実行することは何のメリットがあるのでしょうか? ここでは意味のあることは何もできません。
回避策の 1 つは、コンテキスト インスタンスを AsyncTask に渡すのではなく、Handler
インスタンスに渡すことです。これは機能します: Handler はコンテキストとタスクを緩やかにバインドするため、リークの危険を冒すことなくそれらの間でメッセージを交換できます (そうですか?)。しかし、それは AsyncTask の前提、つまりハンドラーを気にする必要がないという前提が間違っていることを意味します。同じスレッドでメッセージを送受信しているため、Handler を悪用しているようにも見えます (UI スレッドでメッセージを作成し、UI スレッドでも実行される onPostExecute() で送信します)。
さらに、その回避策を使用しても、コンテキストが破棄されると、起動されたタスクの記録がないという問題がまだ残っています。つまり、画面の向きを変更した後など、コンテキストを再作成するときにタスクを再起動する必要があります。これは遅くて無駄です。
これに対する私の解決策 ( Droid-Fu ライブラリに実装されているWeakReference
) は、コンポーネント名から一意のアプリケーション オブジェクトの現在のインスタンスへの s のマッピングを維持することです。AsyncTask が開始されるたびに、呼び出しコンテキストがそのマップに記録され、コールバックごとに、そのマッピングから現在のコンテキスト インスタンスがフェッチされます。これにより、古いコンテキスト インスタンスを参照することがなくなり、コールバックで常に有効なコンテキストにアクセスできるため、そこで意味のある UI 作業を行うことができます。また、参照が弱く、特定のコンポーネントのインスタンスが存在しなくなるとクリアされるため、リークもありません。
それでも、これは複雑な回避策であり、Droid-Fu ライブラリ クラスの一部をサブクラス化する必要があるため、かなり煩わしいアプローチになります。
今、私は単に知りたいのです:私は何かを大幅に見逃しているのでしょうか、それとも AsyncTask は本当に完全に欠陥がありますか? あなたの経験はそれでどのように機能していますか? これらの問題をどのように解決しましたか?
ご意見ありがとうございます。