長時間実行オペレーションのためのAndroid AsyncTask


90

ここにあるAsyncTaskのドキュメントを引用すると、次のようになります。

AsyncTasksは、理想的には短い操作(最大で数秒)に使用する必要があります。スレッドを長期間実行し続ける必要がある場合は、java.util.concurrentパッケージによって提供されるさまざまなAPIを使用することを強くお勧めします。エグゼキューター、ThreadPoolExecutor、FutureTask。

今私の質問が発生します:なぜですか?このdoInBackground()関数はUIスレッドから実行されるため、ここで長時間実行される操作があると、どのような害がありますか?


2
アプリ(asyncTaskを使用する)を実際のデバイスにデプロイするときに直面した問題はdoInBackground、進行状況バーが使用されていない場合、長時間実行される関数が画面をフリーズさせることでした。
venkatKA 2012年

2
AsyncTaskは、起動されたアクティビティに関連付けられているため、アクティビティが強制終了されると、AsyncTaskインスタンスも強制終了されます。
IgorGanapolsky 2014

サービス内にAsyncTaskを作成するとどうなりますか?それで問題は解決しませんか?

1
IntentService、Perfectソリューションを使用して、長時間の操作をバックグラウンドで実行します。
Keyur Thumar 2017

回答:


120

これは非常に良い質問です。Androidプログラマーとして問題を完全に理解するには時間がかかります。実際、AsyncTaskには、関連する2つの主な問題があります。

  • 彼らは活動のライフサイクルとの結びつきが不十分です
  • 彼らは非常に簡単にメモリリークを作成します。

RoboSpice Motivationsアプリ(Google Playで入手可能)内で、その質問に詳細に答えます。AsyncTasks、ローダー、それらの機能と欠点の詳細なビューを提供し、ネットワークリクエストの代替ソリューションであるRoboSpiceも紹介します。ネットワークリクエストはAndroidの一般的な要件であり、本質的に長時間実行オペレーションです。これはアプリからの抜粋です:

AsyncTaskおよびActivityライフサイクル

AsyncTaskは、Activityインスタンスのライフサイクルに従いません。アクティビティ内でAsyncTaskを開始し、デバイスを回転させると、アクティビティが破棄され、新しいインスタンスが作成されます。しかし、AsyncTaskは停止しません。完了するまで生き続けます。

そして、それが完了すると、AsyncTaskは新しいアクティビティのUIを更新しません。実際に、表示されなくなったアクティビティの以前のインスタンスを更新します。たとえば、findViewByIdを使用してアクティビティ内のビューを取得する場合、java.lang.IllegalArgumentException:ビューがウィンドウマネージャーにアタッチされていないタイプの例外が発生する可能性があります。

メモリリークの問題

AsyncTasksをアクティビティの内部クラスとして作成すると非常に便利です。AsyncTaskはタスクの完了時または進行中にアクティビティのビューを操作する必要があるため、アクティビティの内部クラスを使用すると便利です。内部クラスは外部クラスの任意のフィールドに直接アクセスできます。

それでも、これは、内部クラスがその外部クラスインスタンス(アクティビティ)に非表示の参照を保持することを意味します。

長期的には、これによりメモリリークが発生します。AsyncTaskが長時間続く場合、アクティビティは「生きたまま」維持されますが、Androidは表示されなくなるため、アクティビティを削除したいと考えます。アクティビティをガベージコレクションすることはできません。これは、Androidがデバイス上のリソースを保持するための中心的なメカニズムです。


実行時間の長い操作にAsyncTasksを使用するのは非常に悪い考えです。それでも、1秒または2秒後にビューを更新するなど、短命なものには問題ありません。

RoboSpice Motivationsアプリをダウンロードすることをお勧めします。これは実際にこれを詳細に説明し、いくつかのバックグラウンド操作を実行するためのさまざまな方法のサンプルとデモを提供します。


@Snicolasこんにちは。NFCタグからデータをスキャンしてサーバーに送信するアプリがあります。信号が良好な領域では問題なく動作しますが、信号がない場合は、Webcallを実行するAsyncTaskが引き続き実行されます。たとえば、進行状況ダイアログボックスが数分間実行された後、画面が消えると、画面が黒くなり応答しなくなります。私のAsyncTaskは内部クラスです。X秒後にタスクをキャンセルするハンドラーを書いています。アプリはスキャン後数時間で古いデータをサーバーに送信するようです。これは、AsyncTaskが完了せず、数時間後に完了する可能性があるためでしょうか?私はどんな洞察にも感謝します。感謝
カメ少年2013

トレースして、何が起こるかを確認します。しかし、そうです、それはかなり可能です!asynctaskを適切に設計すれば、かなり適切にキャンセルできます。RSまたはサービスに移行したくない場合は、これが良い出発点となるでしょう
Snicolas

@Snicolas返信ありがとうございます。私は昨日SOに私の問題の概要を述べ、8秒後にAsyncTaskを停止するように記述したハンドラーコードを表示して投稿しました。時間があれば、ぜひご覧になっていただけませんか。ハンドラーからAsyncTask.cancel(true)を呼び出すと、タスクが適切にキャンセルされますか?doInBackgroudのiscancelled()の値を定期的に確認する必要があることはわかっていますが、1行のWebコールHttpPostを実行し、UIで更新を公開していないため、状況に当てはまらないと考えています。AsyncTaskの代替手段はありますか?たとえば、IntentServiceからHttPostを作成することは可能ですか
turtleboy '19


RoboSpice(github上)を試してみてください。;)
Snicolas 2013

38

どうして ?

そのためAsyncTask、デフォルトでは、スレッドプール使用しています、あなたが作成しなかったことを。そのプールの要件がわからないので、自分で作成していないプールのリソースを決して拘束しないでください。ここにあるように、そのプールのドキュメントで指示されていない場合は、作成していないプールのリソースを決して拘束しないでください。

特に、Android 3.2以降、AsyncTaskデフォルトで使用されるスレッドプール(android:targetSdkVersion13以上に設定されたアプリの場合)には1つのスレッドしか含まれていません。このスレッドを無期限に結合すると、他のタスクは実行されなくなります。


この説明に感謝します。長時間実行する操作でのAsyncTasksの使用については、本当に欠陥のあるものは何も見つかりませんでした(ただし、通常は自分でサービスに委任します)。そのサイズについての仮定を行わない)スポットオンのようです。サービスの使用に関するAnupの投稿の補足として:そのサービス自体もバックグラウンドスレッドでタスクを実行し、独自のメインスレッドをブロックするべきではありません。オプションはIntentServiceにすることも、より複雑な同時実行性の要件の場合は独自のマルチスレッド戦略を適用することもできます。
2012年

サービス内でAsyncTaskを開始しても同じですか?つまり、長時間の操作はまだ問題でしょうか?

1
@eddy:はい、スレッドプールの性質は変更されません。の場合はService、a Threadまたはを使用しますThreadPoolExecutor
CommonsWare 2014

@CommonsWareは最後の質問に感謝します。TimerTasksはAsyncTasksの同じ欠点を共有していますか?またはそれはまったく別のものですか?

1
@eddy:TimerTaskAndroidではなく、標準のJavaからです。(その名前にもかかわらず、標準Javaの一部として)TimerTaskを支持して主に放棄されましたScheduledExecutorService。どちらもAndroidに関連付けられていないため、これらのものがバックグラウンドで実行されることが予想される場合は、サービスが必要です。そして、あなたは本当にAlarmManager Androidから考慮する必要があるので、時計の刻みを見ているだけでサービスをぶら下げる必要はありません。
CommonsWare 2014

4

Aysncタスクは、まだアプリのGUIで使用するための特別なスレッドですが、UIスレッドのリソースの多いタスクを維持します。したがって、リストの更新、ビューの変更などの操作でフェッチ操作や更新操作を行う必要がある場合は、非同期タスクを使用して、これらの操作をUIスレッドから切り離すことができますが、これらの操作はまだ何らかの方法でUIに接続されていることに注意してください。

UIの更新を必要としない実行時間の長いタスクの場合は、UIがなくても実行できるため、代わりにサービスを使用できます。

したがって、短いタスクの場合は、非同期タスクを使用してください。これは、スポーンアクティビティが終了した後、OSによって強制終了される可能性があるためです(通常、操作の途中で終了せず、タスクを完了します)。また、長くて反復的な作業には、代わりにサービスを使用してください。

詳細については、スレッドを参照してください:

数秒以上のAsyncTask?

そして

AsyncTaskは、アクティビティが破棄されても停止しません


1

AsyncTaskの問題は、アクティビティの非静的内部クラスとして定義されている場合、アクティビティへの参照があることです。非同期タスクのコンテナのアクティビティが終了しても、AsyncTaskのバックグラウンド作業が継続しているシナリオでは、アクティビティオブジェクトへの参照があるため、アクティビティオブジェクトはガベージコレクションされず、メモリリークが発生します。

これを修正するソリューションは、非同期タスクをアクティビティの静的内部クラスとして定義し、コンテキストへの弱い参照を使用することです。

それでも、シンプルで迅速なバックグラウンドタスクに使用することをお勧めします。クリーンなコードでアプリを開発するには、RxJavaを使用して複雑なバックグラウンドタスクを実行し、その結果でUIを更新することをお勧めします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.