Androidでこの頻繁に発生する状況に関する質問があります。
Mainアクティビティがあり、mainactivityの参照とともにAsyncTaskを呼び出して、AsyncTaskがMainActivityのビューを更新できるようにします。
イベントをステップに分解します
上記の解決策は、「Pro Android 4」という本で推奨されているように、AsyncTaskにWeakReferenceを保持することです。
WeakReference<Activity> weakActivity;
in method onPostExecute
Activity activity = weakActivity.get();
if (activity != null) {
// do your stuff with activity here
}
これはどのように状況を解決しますか?
私の質問は、私のasynctaskが10個のファイルをダウンロードしており、5の完了時に(向きの変更のため)アクティビティが再開される場合、FileDownloadingTaskがもう一度呼び出されますか?.
最初に呼び出された以前のAsyncTaskはどうなりますか?
ありがとう、そして質問の長さをおaびします。
これはどのように状況を解決しますか?
WeakReference
を使用すると、Activity
をガベージコレクションできるため、メモリリークは発生しません。
Null参照は、AsyncTask
cannotが、接続されなくなったユーザーインターフェイスを盲目的に更新しようとすることを意味し、例外をスローします(たとえば、ウィンドウマネージャに接続されていないビュー)。もちろん、NPEを避けるためにnullをチェックする必要があります。
私のasynctaskが10個のファイルをダウンロードしており、5の完了時に(方向の変更のため)アクティビティが再開されると、FileDownloadingTaskがもう一度呼び出されますか?.
実装に依存しますが、おそらくそうです-結果をどこかにキャッシュするなど、意図的に繰り返しダウンロードを不要にするために何かをしない場合。
最初に呼び出された以前の
AsyncTask
はどうなりますか?
以前のバージョンのAndroidは、完了するまで実行され、すべてのファイルをダウンロードするだけで、それらを破棄します(実装によってはキャッシュすることもあります)。
新しいAndroidでは、AsyncTask
がそれらを開始したActivity
とともに殺されているのではないかと疑っていますが、私の疑いの根拠は、メモリリークデモが RoboSpice =(以下を参照)私のJellyBeanデバイスで実際にリークしないでください。
アドバイスを提供する場合:AsyncTask
は、ネットワークなどの潜在的に長時間実行されるタスクの実行には適していません。
単一のワーカースレッドが受け入れられる場合、IntentService
はより良い(そして比較的単純な)アプローチです。スレッドプールを制御する場合は、(ローカル)Service
を使用します。メインスレッドで作業しないように注意してください。
RoboSpice バックグラウンドで確実にネットワークを実行する方法を探している場合は良いようです(免責事項:私は試していません;私は提携していません)。 Play Storeには RoboSpice Motivations demo app があり、whyを説明しています。これはAsyncTask
でうまくいかない可能性があります-WeakReferenceの回避策を含みます。
このスレッドも参照してください: AsyncTaskは本当に概念的に欠陥がありますか、それとも何か不足していますか?
更新:
githubプロジェクト を作成し、別のSOの質問にIntentService
を使用してダウンロードする例を示します( How to fix Android.os.NetworkOnMainThreadException ? )しかし、ここでも関連があると思いますonActivityResult
を介して結果を返すことにより、デバイスを回転させたときに飛行中のダウンロードがActivity
を再起動しました。
WeakReference
クラスは、基本的に、JREが特定のインスタンスの参照カウンターを増やすことを防止します。
Javaのメモリ管理には触れず、あなたの質問に直接答えません。WeakReference
は、AsyncTask
に親アクティビティがまだ有効かどうかを知る方法を提供することで状況を解決します。
方向の変更自体は、AsyncTask
を自動的に再起動しません。既知のメカニズム(onCreate
/onDestroy
、onSave/RestoreInstanceState
)。
元のAsyncTask
に関して、これらのオプションのどれが起こるかは100%確信できません。
AsyncTask
を破棄します。これは、参照を保持している唯一のオブジェクト(元のActivity
)が破棄されるためです。AsyncTask
オブジェクトへの参照を維持し、ガベージコレクションをブロックし、バックグラウンドでAsyncTask
を実質的に残しますいずれにしても、AsyncTask
を手動で中断/一時停止および再起動/再開する(または新しいActivity
に引き渡す)か、代わりにService
を使用することをお勧めします。
これはどのように状況を解決しますか?
そうではありません。
WeakReference
のリファレントは、ガベージコレクターがリファレントが弱く到達可能であると判断した場合、null
に設定されます。これは、アクティビティが一時停止されている場合は発生せず、アクティビティが破棄されてフレームワークがそのアクティビティへのすべての参照を破棄したときに必ずしもすぐに発生するわけではありません。 GCが実行されていない場合、AsyncTask
がデッドアクティビティへの参照をまだ含んでいる間にWeakReference
が完了する可能性があります。
それだけでなく、このアプローチはAsyncTask
がCPUを無駄に消費するのを防ぐために何もしません。
より良い方法は、適切なティアダウンライフサイクルメソッドでActivity
にAsyncTask
と cancel(...)
への強い参照を維持させることです。 AsyncTask
は isCancelled()
を監視し、不要になったら動作を停止する必要があります。
AsyncTask
を構成の変更(ただしnot他の形式のアクティビティの破壊)を越えて存続させたい場合は、保持されたフラグメントでホストできます。