公式のAndroid documentation/guide for Looper
、Handler
、およびMessageQueue
を確認しましたが、取得できませんでした。 Androidの新機能であり、これらの概念と非常に混同されました。
Looper
はメッセージ処理ループです。 MessageQueue
からアイテムを読み取り、処理します。 Looper
クラスは、通常 HandlerThread
(Thread
のサブクラス)と組み合わせて使用されます。
Handler
は、主にメッセージとLooper
オブジェクトをスレッドのRunnable
に投稿することにより、MessageQueue
との対話を容易にするユーティリティクラスです。 Handler
が作成されると、特定のLooper
(および関連するスレッドとメッセージキュー)にバインドされます。
通常の使用法では、HandlerThread
を作成して開始し、Handler
オブジェクトを作成して、他のスレッドがHandlerThread
インスタンスと対話できるようにします。 Handler
は、HandlerThread
で実行中に作成する必要がありますが、一度作成すると、Handler
のスケジューリングメソッド(post(Runnable)
など)を使用できるスレッドに制限はありません。 )
Androidアプリケーションのメインスレッド(別名UIスレッド))は、アプリケーションインスタンスが作成される前にハンドラースレッドとして設定されます。
クラスのドキュメントとは別に、このすべてについて素晴らしい議論があります here 。
追伸上記のすべてのクラスはパッケージAndroid.os
。
ルーパーから始めましょう。 Looperとは何かを理解すると、Looper、Handler、MessageQueueの関係をより簡単に理解できます。また、GUIフレームワークのコンテキストでLooperが何であるかをよりよく理解できます。ルーパーは2つのことを行うように作られています。
1)ルーパーは、通常のスレッドを変換します。このスレッドは、run()
メソッドが戻ると終了します GUIフレームワークで必要なAndroidアプリが実行中)まで継続的に実行されます(技術的には、run()
メソッドが戻ると終了します。以下で私が意味することを明確にします)。
2)ルーパーは、実行されるジョブがエンキューされるキューを提供します。これはGUIフレームワークでも必要です。
ご存知かもしれませんが、アプリケーションが起動すると、システムは「main」と呼ばれるアプリケーションの実行スレッドを作成し、Androidアプリケーションは通常、デフォルトで完全に単一のスレッドで実行され、しかし、メインスレッドは秘密ではなく、特別なスレッドです。これは、new Thread()
で作成できる通常のスレッドですこれは、run()
メソッドが戻ったときに終了することを意味します!以下の例を考えてください。
public class HelloRunnable implements Runnable {
public void run() {
System.out.println("Hello from a thread!");
}
public static void main(String args[]) {
(new Thread(new HelloRunnable())).start();
}
}
ここで、この単純な原則をAndroidアプリに適用します。Androidアプリが通常のスレッドで実行されるとどうなりますか? 「UI」または何でもアプリケーションを起動し、すべてのUIを描画します。したがって、最初の画面がユーザーに表示されます。それで、今はどうなりますか?メインスレッドは終了しますか?いいえ、そうすべきではありません。どうすればこの動作を実現できますか?さて、Object.wait()
またはThread.sleep()
で試すことができますたとえば、メインスレッドが最初のジョブを終了して最初の画面を表示し、スリープします。これまでのところは良いですが、現時点では、複数のジョブを保持するためにキューのようなデータ構造が必要です。ユーザーが画面を連続してタッチし、タスクに時間がかかる場合を考えてくださいしたがって、先入れ先出し方式で実行されるジョブを保持するためのデータ構造が必要になります。また、割り込みを使用して、常に実行およびプロセスジョブ到着スレッドを実装することも想像できます。 eではない複雑で、しばしば維持できないコードにつながります。むしろ、そのような目的のために新しいメカニズムを作成し、それがLooperの目的です 。 Looperクラスの公式ドキュメント は、「スレッドにはデフォルトでメッセージループが関連付けられていません」とあり、Looperは「スレッドのメッセージループを実行するために使用される」クラスです。これで、その意味を理解できます。
HandlerとMessageQueueに移動しましょう。まず、MessageQueueは上で述べたキューです。ルーパー内にあり、それだけです。 Looperクラスのソースコード で確認できます。ルーパークラスには、MessageQueueのメンバー変数があります。
次に、ハンドラーとは何ですか?キューがある場合、新しいタスクをキューにエンキューできるメソッドがあるはずですよね?それがHandlerのすることです。さまざまなpost(Runnable r)
メソッドを使用して、新しいタスクをキュー(MessageQueue)にエンキューできます。それでおしまい。これは、すべてLooper、Handler、およびMessageQueueについてです。
私の最後のWordは、基本的にLooperはGUIフレームワークで発生する問題に対処するために作られたクラスです。しかし、このようなニーズは他の状況でも発生する可能性があります。実際、これはマルチスレッドアプリケーションの非常に有名なパターンであり、Doug Leaによる「Javaでの同時プログラミング」で詳しく学ぶことができます(特に4.1.4の「Worker Threads」が役立ちます)。また、この種のメカニズムはAndroidフレームワークでは一意ではありませんが、すべてのGUIフレームワークはこれに多少似ている必要があります。ほとんど同じメカニズムがJava Swingフレームワーク。
MessageQueue
:Looper
によってディスパッチされるメッセージのリストを保持する低レベルのクラスです。メッセージはMessageQueue
に直接追加されるのではなく、Handler
に関連付けられたLooper
オブジェクトを通じて追加されます。[]
Looper
:ディスパッチされるメッセージを含むMessageQueue
をループします。キューを管理する実際のタスクは、メッセージキュー内のメッセージの処理(追加、削除、ディスパッチ)を担当するHandler
によって行われます。[ 2 ]
Handler
:スレッドのMessage
に関連付けられたRunnable
およびMessageQueue
オブジェクトを送信および処理できます。各Handlerインスタンスは、単一のスレッドとそのスレッドのメッセージキューに関連付けられています。[ 4 ]
新しいHandler
を作成すると、それを作成しているスレッドのスレッド/メッセージキューにバインドされます-その時点から、メッセージと実行可能ファイルを配信しますそのメッセージキューとがメッセージキューから出てくるときにそれらを実行します。
理解を深めるために、下の画像[ 2 ]をご覧ください。
MessageQueueは、メッセージループまたはメッセージキューであり、基本的にはメッセージまたは実行可能ファイル(実行可能コードのセット)のリストが含まれています。
つまり、MessageQueueは、処理する必要のあるメッセージと呼ばれるタスクを持つキューです。
注:AndroidメインスレッドでMessageQueueを維持します。
Looper:
ルーパーは、現在のスレッドのMessageQueueを提供するワーカーです。ルーパーはメッセージキューをループし、対応するハンドラーにメッセージを送信して処理します。
どのスレッドにも一意のルーパーを1つだけ設定できます。この制約は、ThreadLocalストレージの概念を使用して実現されます。
LooperとMessageQueueの利点
以下に説明するように、LooperとMessageQueueを使用することにはいくつかの利点があります。
・MessageQueueの使用により、実行がシーケンシャルになるため、同時スレッドの場合、これにより競合状態が回避されます。
・通常、スレッドはジョブが完了すると再利用できません。ただし、Looperを使用したスレッドは、quitメソッドを呼び出すまで有効な状態に保たれるため、バックグラウンドでジョブを実行するたびに新しいインスタンスを作成する必要はありません。
ハンドラー:
ハンドラーを使用すると、他のバックグラウンドスレッドからUIスレッドと通信できます。これは、Android as Androidでは、他のスレッドがUIスレッドと直接通信することを許可しません。
ハンドラーを使用すると、スレッドのMessageQueueに関連付けられたMessageおよびRunnableオブジェクトを送信および処理できます。各Handlerインスタンスは、単一のスレッドとそのスレッドのメッセージキューに関連付けられています。
新しいハンドラーを作成すると、それを作成しているスレッドのスレッド/メッセージキューにバインドされます。その時点から、メッセージと実行可能ファイルをそのメッセージキューに配信し、メッセージキューから出て実行します。 。
ハンドラーには主に2つの用途があります。
(1)将来のある時点として実行されるメッセージと実行可能ファイルをスケジュールする。つまり、将来同じスレッドでアクションを実行します。
(2)自分のスレッドとは異なるスレッドで実行されるアクションをキューに入れること。言い換えると、異なるスレッドで実行するアクションをキューに入れます。