Androidコアについて:Looper、Handler、およびHandlerThread

Android Coreについて:Looper、Handler、およびHandlerThread

この記事では、Android Looper、Handler、およびHandlerThreadについて説明します。 これらは、Android OSのビルディングブロックの一つです。

私自身の経験では、私は最近まで非常に限られた文脈でそれらを使用してきました。 私のユースケースでは、主に他のスレッドからUIを更新するために、main/uiスレッドにタスクを送信することが含まれていました。 マルチスレッド操作の他の側面は、ThreadPoolExecutor、IntentService、AsyncTaskなどの別の方法で処理されました。

マルチスレッドとタスクの実行は古い科目です。 Java自体にはjavaがあります。ユーティルそれを容易にするための並行パッケージとFork/Joinフレームワーク。 いくつかのライブラリは、非同期操作を合理化するために書かれています。 RxJavaは、リアクティブプログラミングと非同期アプリケーションの設計のための今日の最も人気のあるラ

だから、なぜ私は古い学校について書いていますか?

Looper, Handler, そしてHandlerThreadは、非同期プログラミングの問題を解決するAndroidの方法です。 彼らは古い学校ではなく、複雑なandroidフレームワークが構築されているきちんとした構造です。

新しい開発者にとっては、その背後にある原則を理解し、経験豊富な人はこのトピックを再訪して小さな詳細を思い出すことを強くお勧めします。

私はまた、この主題のためのビデオチュートリアルを作成している、と私は非常にそれを見ることをお勧めします。 今見るにはここをクリック。

ユースケース:

  1. AndroidのメインスレッドはLooperHandlersで構築されています。 そのため、ブロックされていない応答性の高いUIを作成することが不可欠です。
  2. ライブラリを書いている開発者は、ライブラリのサイズのために第三者のライブラリを使用する余裕がありません。 だから、彼らのために、最良の選択肢は、既存の利用可能なリソースを利用することです。 それのための独自のソリューションを書くことは、常にそのレベルの効率と最適化を得るとは限りません。
  3. Sdkを出荷する企業/個人に対しても同じ議論ができます。 クライアントは様々な実装を持つことができますが、それらのすべてが共通のandroidフレームワークApiを共有します。
  4. それらを完全に理解することで、一般的にAndroid SDKとパッケージクラスに従う能力が向上します。

アンケートで探査/改訂を始めましょう。

私は読者がjavaスレッドの基本的な理解を持っていることを期待しています。 必要に応じて、java ThreadとRunnableの概要を入手してください。

javaスレッドの問題は何ですか?

Javaスレッドは一度だけ使用され、runメソッドを実行した後に終了します。

改善できますか?

糸は諸刃の剣である。 実行のスレッド間でタスクを配布することで実行を高速化できますが、スレッドが過剰になったときにも実行を遅くすることができます。 スレッドの作成自体はオーバーヘッドです。 したがって、最良の選択肢は、最適な数のスレッドを持ち、タスクの実行に再利用することです。

糸の再利用性のためのモデル:

  1. スレッドは、run()メソッドを介してループ内で生きています。
  2. タスクはそのスレッドによって連続的に実行され、キュー(MessageQueue)に維持されます。
  3. 完了したらスレッドを終了する必要があります。

それを行うAndroidの方法は何ですか?上記のモデルは、LooperHandlerHandlerThreadを介してAndroidに実装されています。 システムは記事のカバーのように車であるために視覚化することができる。

  1. MessageQueue 処理する必要があるメッセージと呼ばれるタスクを持つキューです。
  2. HandlerLooperを使用してMessageQueue内のタスクをキューに入れ、タスクがMessageQueueから出てくるときにもそれらを実行します。
  3. Looperは、スレッドを生きたままにし、MessageQueueをループし、対応するhandlerにメッセージを送信して処理するワーカーです。
  4. 最後にThreadはLooperのquit()メソッドを呼び出して終了します。

一つのスレッドは一つの一意のルーパーのみを持つことができ、それに関連付けられた多くの一意のハンドラを持つことができます。

スレッドのLooperとMessageQueueを作成する:

スレッドは、実行後にLooper.prepare()を呼び出すことによってLooperMessageQueueを取得します。 Looper.prepare()は呼び出し元スレッドを識別し、LooperおよびMessageQueueオブジェクトを作成し、threadThreadLocalストレージクラスで関連付けます。 関連するルーパーを開始するには、Looper.loop()を呼び出す必要があります。 同様に、looperlooper.quit()を介して明示的に終了する必要があります。

class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here // this will run in non-ui/background thread } }; Looper.loop(); } }

スレッドのハンドラを作成する:

AHandlerは、スレッドのLooperを介してインスタンス化するスレッドに暗黙的に関連付けられますが、Handlerのコンストラクタ

handler = new Handler() {@Overridepublic void handleMessage(Message msg) { // process incoming messages here // this will run in the thread, which instantiates it }};

Handlerを介してMessageQueueにメッセージを送信するには、二つのモードで行うことができます:

  1. Message: これは、メッセージデータを処理するための様々な有用なメソッドを定義するクラスです。 オブジェクトを送信するには、obj変数を設定します。
Message msg = new Message();msg.obj = "Ali send message";handler.sendMessage(msg);

Messageクラスの詳細な概要はここにあります: https://developer.android.com/reference/android/os/Message.html

Runnable: runnableはMessageQueueに投稿することもできます。 例:メインスレッドでタスクを投稿して実行する。

new Handler(Looper.getMainLooper()).post(new Runnable() {@Overridepublic void run() { // this will run in the main thread }});

上記の例では、Handlerを作成し、メインスレッドに関連付けられたLooperを提供します。 これは、このハンドラをメインスレッドに関連付けます。 Runnableを投稿すると、メインスレッドのMessageQueueにキューに入れられ、メインスレッドで実行されます。

ハンドラは、ここで見つけることができるさまざまな方法でメッセージ操作が可能です: https://developer.android.com/reference/android/os/Handler.html

独自のスレッドを作成し、LopperMessageQueueを提供することは、問題に対処する正しい方法ではありません。 そのため、Androidはプロセスを合理化するためにHandlerThreadThreadのサブクラス)を提供しています。 内部的には、私たちが行ったのと同じことを行いますが、堅牢な方法で行います。 そのため、常にHandlerThreadを使用してください。

HandlerThreadを作成する方法の一つは、それをサブクラス化することであり、ほとんどの場合、このメソッドを使用します。

private class MyHandlerThread extends HandlerThread { Handler handler; public MyHandlerThread(String name) { super(name); } @Override protected void onLooperPrepared() { handler = new Handler(getLooper()) { @Override public void handleMessage(Message msg) { // process incoming messages here // this will run in non-ui/background thread } }; }}

注:onLooperPrepared()が呼び出されたときにハンドラをインスタンス化しました。 したがって、そのHandlerはそのLooperに関連付けることができます。

  1. Looper HandlerThreadのstart()が呼び出された後、つまりスレッドが実行された後にのみ準備されます。
  2. AHandlerHandlerThreadに関連付けることができますが、それはLooperが準備された後でなければなりません。

HandlerThreadを作成する他の方法:

HandlerThread handlerThread = new HandlerThread("MyHandlerThread");handlerThread.start();Handler handler = new Handler(handlerThread.getLooper());

メモ: HandlerThreadは、リソースを解放してスレッドの実行を停止するためにmyHandlerThread.quit()を呼び出す必要があります。

私は上記のコードを練習することをお勧めしますので、あなたは彼らの小さな詳細を把握することができます。

郵便局シミュレーションのサンプルプロジェクトを作成しました。 郵便局はHandlerThreadに造られ、顧客は郵便局の助けによって伝達し合う。 Simulatorクラスは、少数のクライアントボットを作成し、その通信をMainActivityに委任します。

この例へのリンク

私はまた、この主題のためのビデオチュートリアルを作成している、と私は非常にそれを見ることをお勧めします。 今見るにはここをクリック。

また、Twitter、Linkedin、Github、Facebookで友達になりましょう。

学習は旅です、一緒に学びましょう!

コメントを残す

メールアドレスが公開されることはありません。