Androidメッセージメカニズム(3):Looper
5440 ワード
LooperのAndroidメッセージメカニズムにおける主な役割は、MessageQueueからMessageを常にループして取り出し、Messageを取り出して渡したtargetであり、このtargetはHandlerオブジェクトであり、メッセージをHandlerに渡した後にHandlerを呼び出す
クラスメンバー
filed
意味
説明
sThreadLocal
Looperオブジェクト
各スレッドのLooperオブジェクトは、スレッドローカルストレージ(TLS)オブジェクトである.
sMainLooper
メインスレッドで使用されるLooperオブジェクト
Activity Threadマスタースレッドでシステムによって作成されます.
mQueue
Looper対応メッセージキュー
1つのLooperは1つのメッセージキュー(1対1)に依存する
mThread
Looper対応スレッド
1つのLooperと1つのスレッドバインド(1対1)
Looper作業プロセススレッドのメッセージループを作成するためにLooperオブジェクトを使用する場合、スレッドのLooperオブジェクトを作成するために、静的prepareメソッドまたはprepareMainLooperメソッドが呼び出されます.プライマリ・スレッドの場合はprepareMainLooperが呼び出され、通常のスレッドの場合はprepareメソッドを呼び出すだけで、両方ともprepareメソッドが呼び出されます.このメソッドのソースは次のとおりです.
prepare()メソッドを最初に呼び出すと、新しく作成された現在のスレッドに対応するLooperオブジェクトがメッセージループLooperクラスないしAndroidメッセージ処理メカニズムの核心部分を開く、Looperを使用する場合、 MessageQueueの次のMessage を読み込む Messageを対応するtarget(Handler)に配布して を処理する.配布されたMessageを、 を多重化するためにメッセージプールに回収する.
上記のコードには、debug用のloggingメソッドが表示されます.デフォルトではlogging==nullで、setMessageLogging()を設定してdebug作業を開始します.メッセージループ
得られたLooperオブジェクトはHandlerの構築関数パラメータとすることができ,後述する.終了メッセージループは主に終了メッセージキューである:
その他の方法 Looper構築メソッドLooperは、静的メソッド prepareMainLooper()この方法はメインスレッドでのみ呼び出され、システムはすでに私たちを助けてくれて、私たちは一般的に使わなくても呼び出すことができません.
dispatchMessage()
方法で処理することである.クラスメンバー
filed
意味
説明
sThreadLocal
Looperオブジェクト
各スレッドのLooperオブジェクトは、スレッドローカルストレージ(TLS)オブジェクトである.
sMainLooper
メインスレッドで使用されるLooperオブジェクト
Activity Threadマスタースレッドでシステムによって作成されます.
mQueue
Looper対応メッセージキュー
1つのLooperは1つのメッセージキュー(1対1)に依存する
mThread
Looper対応スレッド
1つのLooperと1つのスレッドバインド(1対1)
Looper作業プロセス
/**
* Looper ,Looper MessageQueue , Looper TLS
* @param quitAllowed
*/
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
// Looper Looper , looper。
throw new RuntimeException("Only one Looper may be created per thread");
}
// TLS Looper
sThreadLocal.set(new Looper(quitAllowed));
}
prepare()メソッドを最初に呼び出すと、新しく作成された現在のスレッドに対応するLooperオブジェクトが
TLS
オブジェクトに格納され、呼び出しを繰り返すとエラーが表示されます.Looper.prepare()
を呼び出した後、Looperを呼び出す必要がある.loop()メソッドはメッセージループを開きます.この方法は、メッセージがないときにループを終了するまで、デッドループが次の操作を繰り返します. /**
* , {@link #quit()}
*
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();// TLS Looper
if (me == null) {// Loop.prepare() ,
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;// Looper
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
// , 。
final long ident = Binder.clearCallingIdentity();
// , ,
for (;;) {
// MessageQueue next , ,next , ,loop next 。
Message msg = queue.next(); // might block, , 。
// , , , 。 ,
// 。
if (msg == null) {
// No message indicates that the message queue is quitting.
// 。 Looper quit() 。
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;// null, setMessageLogging() , debug
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg); //msg.target Handler , dispatchMessage
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();// identity
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked(); //
}
}
上記のコードには、debug用のloggingメソッドが表示されます.デフォルトではlogging==nullで、setMessageLogging()を設定してdebug作業を開始します.
myLooper()
を取得する方法は、現在のメッセージループオブジェクトを取得するために使用される.Looperオブジェクトは、メンバー変数sThreadLocal( (TLS)
)から取得されます.得られたLooperオブジェクトはHandlerの構築関数パラメータとすることができ,後述する.
public void quit() {
mQueue.quit(false);//
}
public void quitSafely() {
mQueue.quit(true);
}
その他の方法
Looper.loop()
を実行するときにLooperの構築関数を呼び出す(コードは前述を参照).Looperが初期化されると、新しいMessageQueueのオブジェクトがメンバーmQueueに保存されます.Looperはスレッドとメッセージキューに依存します. private Looper(boolean quitAllowed) {
// Looper ,
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}