コンポーネントのかなり大きなリストがあり、それぞれがわずかに異なることに対処しています。私の経験における 2 つの主な競合は、実際にはHandlersとExecutorsの間、およびTasksとThreadsの間です。
概要
スレッド
スレッドは、並行性を促進するために使用される基本的なシステム メカニズムです。スレッドは Windows、Unix などに存在し、システムに適した方法で実装できます。通常、スレッドの作成にはかなりのコストがかかります (完全に新しいプロセスを作成するにはさらにコストがかかります)。 Dalvik VM が Linux スレッドに依存しているか、独自の Thread 実装を提供しているかはわかりません。 このDalvik 仮想マシン アーキテクチャ ドキュメントによると、Dalvik VM はスレッドの実装に Linux スレッド モデルを使用するだけです。ただし、Dalvik VM は、Android 4.0 より前の Java 言語仕様のメモリ モデルに準拠していません。
ご存じかもしれませんが、スレッドの作成にはコストがかかるため、多くの非同期計算をスケジュールするより良い方法は、管理されたスレッドのプール (サイズは基盤となるハードウェアの機能に依存します) を使用し、単純にタスクをマネージャーにフィードすることです。これにより、スレッドが使用可能になったときにタスクがスケジュールされます。
Android ハンドラ
私が理解している歴史の簡単な概要は、Java Executorライブラリ/API が固まる前に Android 開発が始まったということです。利用可能な古いThreadsおよびSynchronizationメソッドよりも混乱の少ない同時実行インターフェイスを提供し、スレッド間のメッセージの受け渡しを適切な方法で容易にするために、Android はHandlersを導入しました。ただし、これを間違って理解している場合を除き、ハンドラーは基本的にエグゼキューターと同じものです。メッセージ (Runnable を含む)、または単に Runable を Handler に渡すと、これらのメッセージはキューに入れられ、Handler のスレッドが処理できる限り迅速に実行されます。
Java エグゼキュータ
Android では、スレッド間のすべての通信は、スレッドのハンドラーを介して行われます (またはそうすべきです) (私の知る限り、別のスレッドのメモリに直接アクセスしていて、同期が必要な場合を除きます)。新しい Java では、Executor は機能的には Handler と同等であり、FutureTask は Message と同等です。ランナブルは依然としてランナブルです。Runnable は、コードを単に実行する必要がある場合に使用されます。FutureTask は、計算を非同期で実行する必要があり、計算から結果を取得する必要がある場合に使用されます。結果は、どのタイプのオブジェクトでも可能です。FutureTask は Future インターフェースを実装しているため、Future が解決されて結果が得られるまで 1 つのスレッドで簡単に待機することもできます。
ローダー
ローダーは、(アクティビティによって消費される) データをロードするための再利用可能なメカニズムを提供する試みです。ドキュメントにもかかわらず、Loader クラスは抽象的ではなく、データの非同期取得だけに使用する必要もありません (ただし、同期ロードに使用するケースは考えられませんが、それについては調べていません)。 . AsyncTaskLoaderは、単に AsyncTask を使用して、データのロードを担当するローダーのメソッドを実行します。ローダーはまったく必要ありません。
例
スレッド
スレッドはエグゼキューターまたはハンドラーをサポートするために使用する必要があります。そうでない場合は、スレッドが必要な場合 (サービスをサポートする場合など) がわかります。一般に、自由な方法で作成、実行、および破棄される小さなタスクのスレッドは避ける必要があります。
ハンドラーとエグゼキューター
私の経験では、UI スレッド (Activity および/または View 階層を実行) と他のスレッドとの間のメッセージの受け渡しを処理する場合は、Handler を使用することをお勧めします。ただし、独自の非同期機能を実装する場合は、エグゼキューターまたはハンドラーのいずれかを使用しても完全に安全と思われます。たとえば、サーバーから取得する画像のキューを管理するクラスがあるとします。独自のエグゼキュータを作成し、必要に応じてそのエグゼキュータにタスクをフィードするだけです。しかし、画像の 1 つが読み込まれ、結果のデータでビューを設定する必要があるというメッセージ メッセージをアクティビティに戻す場合、アクティビティのハンドラーを使用して最良の結果が得られました (runOnUiThread()
メソッド) アクティビティのスレッドで実行されるエグゼキューターを作成し、それに Runnables をポストするのとは対照的です。後者が常に機能しない理由は不明ですが (つまり、ドキュメントから)、そうすると、ハンドラーのrunWithScissors()
メソッドと同様の動作になる可能性があると思います。 (編集、1つのスレッドで複数の同時「ルーパー」を実行することは非常に悪い習慣であることに気づきました-それで説明します。)
経験則としては、次のようになると思います。
- Android コンポーネント間でメッセージを渡すときにハンドラーを使用します。
- 独自のライブラリまたはユーティリティ機能を実装する場合は、Executor または Handler を使用します。
Runnables vs FutureTasks vs AsyncTasks
前述のように、Runnables は、オブジェクト間で計算を渡すために使用される単純なインターフェイスです。スレッド/エグゼキューター/ハンドラーが関係している場合にのみ Runnables を使用する必要はありません。状態をキャプチャしてコードを再利用するために使用できます。
- Runnables と FutureTasks は Executor で使用されます。
- AsyncTasks は (暗黙的に) Handlers で使用されます。AsyncTask を構築するときは、アクティビティへの参照を提供します。AsyncTask クラスは、ワーカー スレッドのプールから 1 つのスレッドで doInBackground メソッドの実行を容易にします (これは Executor によって内部的に管理されます)。これを行うには、ハンドラを使用して、アクティビティ スレッドとタスクのスレッドの間でメッセージを渡します。ただし、タスク自体は Executor によって管理され、ワーカー スレッドが使用可能になったときにそのスレッドに引き渡されます。
ローダー
ローダーは使いません。ただし、アクティビティで使用するためにロードする必要があるデータがある場合に使用できます。データの処理に関して ContentProvider のイディオムに従っている場合は、ContentProvider で CursorLoader を使用できます。
ボレー
私はボレーを使ったことがないので、そのチャンネルについて有益な洞察を持っているとは思えません.
免責事項: 私は Android の歴史の権威ではありません。とにかく、概要が明確さを増すのに役立つことを願っています.