Androidシステムでのメッセージ処理Looper、Handler、Message


Androidシステムでのメッセージ処理
原理:Androidシステムでは、各スレッドに一意のLooperインスタンスを持つことができ、Looperのコンストラクション関数で一意のメッセージキューMessageQueueを作成することができます.すなわち、MessageQueueはスレッドにとって一意です.Androidアプリケーションは起動時にデフォルトでメインスレッドとしてLooperインスタンスを作成し、MainLooperと呼ばれ、里関連のHandlerとLooperのMessageQueueを利用してActivity、Service、BroadcastReceiverなどのコンポーネントの管理を完了します.サブスレッドでは、Looperは呼び出しLooperを表示する必要があります.Prepare()インスタンスを作成します.Prepare()は、ThreadLocalによって、このThread内にLooperインスタンスが1つしかないことを保証する.    
Handlerは作成時に指定Looperを表示することができ、sendMessage()配信メッセージを呼び出すと指定したLooperの中のMessageQueueにメッセージが追加されます.Looperを指定しない場合、Handlerはスレッドを作成するLooperをデフォルトでバインドします.
 
メッセージ処理フロー:(1)Messageオブジェクトをラッピングし、Handler、コールバック関数Runnable callback、データオブジェクトObjectなどを指定する
(2)Handlerを呼び出すsendMessageまたはpost()HandlerバインドされたLooperオブジェクトへのメッセージキューMessageQueue
(3)Looperオブジェクトのloop()メソッドは,MessageQueueからメッセージをループして取り出す処理を行う.
(4)MessageバインドHandlerオブジェクトであるmsgを呼び出す.targetはdispatchMessage()を呼び出してメッセージの処理を完了する.
 
ここでdispatchMessage()メソッドでは,Messageをどのように処理するかはユーザ自身で定義できる.
1)Messageのcallbackが設定されている場合はrun()関数を呼び出してメッセージの処理を行う
 
2)Handler内mCallback(Callbackインタフェースを実現したhandleMessage)が設定されている場合はhandleMessage()で処理する
3)最後にHandlerに継承されhandleMessage()メソッドを実装したサブクラスがこのhandleMessage()によって処理される.
 
Message:    
メッセージは、スレッド間通信のデータユニットで、様々な情報をカプセル化することができ、AndroidシステムではメッセージはMessageクラスでカプセル化されています.MessageというクラスはParcelableインタフェースを実現しているので,IntentやIPCで伝達できる.Handlerオブジェクトに送信できるメッセージを定義し、メッセージの記述と任意のデータオブジェクトを含む.主に2つのintタイプフィールドと1つのObjectタイプフィールドを含む.メッセージはMessageのコンストラクション関数で生成できますが、一般的にMessageを呼び出すことによって生成されます.Obtain()メソッドまたはHandler.obtainMessage()メソッドは、メッセージを構築します.
 
public  :
	public int what			//          ,      
	public int arg1		
	public int arg2
	public Object obj		//           
	public Messenger replyto	//      Messenger  
	
	Bundle data;
	Handler target;			//        Handler  
	Runnable callback;		//        
	
public  :
	public Rnnable getCallback()
	public Bundle getData()
	public void setData(Bundle bundle)
	public void setTarget(Handler target)
	public Handler getTarget()	
	public void sendToTarget()
	public static Message obtain()
	public static Message obtain(Message orig)	// m.data = new Bundle(orig.data);
	public static Message obtain(Handler h)
	public static Message obtain(Handler h, Runnable callback)	// m.callback = callback;
	public static Message obtain(Handler h, int what)
	public static Message obtain(Handler h, int what, Object obj)
	public static Message obtain(Handler h, int what, int arg1, int atg2)
	public static Message obtain(Handler h, int what, int arg1, int arg2, Object obj) {
		Message m = obtain();
		m.target = h;
		m.what = what;
		m.arg1 = arg1;
		m.arg2 = arg2;
		m.obj = obj;
		return m;
	}
	

 
Handler:
主にMessageのクラスを処理し、Messageをメッセージキューに追加し、メッセージキュー内のメッセージを処理します.一般にHandlerのインスタンスは、スレッドとスレッドのメッセージキューとともに使用され、新しいHandlerインスタンスが作成されると、システムはインスタンスをスレッドとスレッドのメッセージキューにバンドルし、メッセージとrunnableオブジェクトをメッセージキューに送信し、メッセージキューの出口で処理することができます.2つの主要な役割:1)メッセージまたはRunnableをスレッド内のある期間に実行するようにスケジュールします.2)ある動作を別のスレッドで実行するように手配する.
class Handler {
//     :
	public interface Callback {
		public boolean handleMessage(Message msg)
	}
	
	final MessageQueue mQueue;
	final Looper mLooper;
	final Callback mCallback;
	IMessenger mMessenger;
	
	public void handleMessage(Message msg)		//     Handler         

//     
	public Handler() {
		.....
		mLooper = Looper.myLooper()	//       Looper  
		mQueue = mLooper.mQueue;	//    Looper   MessageQueue      MessageQueue,    Handler            Looper   
		mCallback = null;
	}
	
	//  Callback      
	public Handler(Callback callback) {
		mLooper = Looper.myLooper();	//	       Looper  
		mQueue = mLooper.mQueue;
		mCallback = callback;
	}
	
	public Handler(Looper looper) {		// 	       Looper  
		mLooper = looper;
		mQueue = looper.mQueue;
		mCallback = null;
	}

	public Handler(Looper looper, Callback callback) {	
		mLooper = looper;		// 	       Looper  
		mQueue = looper.mQueue;		
		mCallback = callback;		
	}
// obtain   
	public final Message obtainMessage(int what);
	public final Message obtainMessage(int what, Object obj)
	public final Message obtainMessage(int what, int arg1, int arg2)
	public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
	public final Message obtainMessage() {
		return Message.obtain(this);
	}
	
// post   Runnable   
	public final boolean postAtTime(Runnable r, long uptimeMillis);
	public final boolean postAtTime(Runnable r, Object token, long uptimeMillis);
	public final boolean postDelayed(Runnable r, long delayMillis);
	public final boolea postAtFrontOfQueue(Runnable r)
	public final boolean post(Runnable r)	{
		sendMessageDelayed(getPostMessage(r), 0);
	}
	  :
	private final getPostMessage(Runnable r) {
		Message m = Message.obtain();	//        Message target = null
		m.callback = r;	//    dispatchMessage        r.run()  
		return m;
	} 
	
// send   
	public final boolean sendMessageAtFrontOfQueue(Message msg)	//          
	public final boolean sendMessageDelayed(Message msg, long delayMillis)	//     
	public final boolean sendMessage(Message msg)			//          
	public final boolean sendEmptyMessage(int what)			//       
	public boolean sendMessageAtTime(Message msg, long uptimeMillis) {	//     uptimeMillis      
		MessageQueue queue = mQueue;
		if(queue != null) {
			msg.target = this;
			return queue.enqueueMessage(msg, uptimeMillis);	//     
		}
	}
	
// dispatch   
	public void dispatchMessage(Message msg) {	
		if(msg.callback != null) {
			handleCallback(msg);	//      msg.callback.run()
		} else {
			if(mCallback != null) {
				mCallback.handleMessage(msg);	//          Callback     
				return;
			}
			handleMessage(msg);	//           handleMessage()  
		}
	}
}

 
Looper: 
Looperの主な役割はループ反復MessageQueueであり,デフォルトではスレッドに関連付けられたメッセージループはなく,スレッドでprepare()メソッドを呼び出してループを実行しなければならない.しかし、ActivityのMain()関数では、システムがデフォルトで呼び出されているので、getMainLooper()でMainLooperを取得できます.
public class Looper {
	
	static final ThreadLocal<Looper> sThreadLocal =  new ThreadLocal<Looper>();
	final MessageQueue mQueue;	//     
	final Thread mThread;		//     
	volatile boolean mRun;		
	private static Looper mMainLooper = null;

	public static void prepare() {	//  TLS     Looper  ,          Looper
		return sThreadLocal.set(new Looper());
	}
	
	public static Looper myLooper() { 	//        Looper  
		return sThreadLocal.get();
	}
	
	public static void prepareMainLooper() {
		prepare();
		setMainLooper(myLooper());	// mMainLooper = looper;   MainLooper
		myLooper().mQueue.mQuiotAllowed = false;	// MainLooper mQuitAlloweed false     
	} 
	
	//    
	public static void loop() {
		Looper me = myLooer();
		MessageQueue queue = me.mQueue;
		while(true) {
			Message msg = queue.next(); //             ,     
			if(msg.target == null) {
				return;
			}
			msg.target.dispatchMessage(msg);	//     ,  Handler.dispatchMessage()
			msg.recycle();	// free  
		}
	}
	public static MessageQueue myQueue() {
		return myLooper().mQueue;
	}
	
	//     
	private Looper() {
		mQueue = new MessageQueue();
		mRun = true;
		mThead = Thread.currentThread();
	}
	
	public void quit() {
		Message msg = Message.obtain();
		mQueue.enqueueMessage(msg, 0);	// msg->target = null         
	}	
}

 
一般に、スレッドAにLooperオブジェクトを作成し、run()メソッドでLooperを呼び出すことができます.loop()メッセージループを開きます.次に、別のスレッドBにHandlerを作成し、AスレッドのLooperインスタンスにバインドする.これにより、Bスレッドでメッセージを送信すると、Aスレッドで処理されます.Looperを指定しない場合、デフォルトでは現在のスレッドのLooperで処理されます.次のようになります.
class MyThread extends Thread {
	public Looper myLooper = null;
	
	public void run() {
		Looper.prepare();
		myLooper = Looper.myLooper();
		Looper.loop();	//     
	}
}

{   2 :
	MyThread thread = new MyThread();
	thread.start();	//     
	Handler handler = new Handler(thread.myLooper);	//        Looper  
	handler.sendMessage();
}

しかし、スレッド2で使用されているLooperオブジェクトがスレッド1で作成された場合、スレッド2でこのLooperを使用する前に作成されたスレッド1であるにもかかわらず、以前のスレッド1でLooperオブジェクトが作成されたことを保証することはできません.この場合、スレッド1のLooperオブジェクトが作成されていない可能性があります.これにより、スレッド2で使用されるLooperはnullである.
このAndroidシステムは私たちに特別なHandlerThreadの完璧な結末を提供してくれました.
public class HandlerThread extends Thread {
	public Looper getLooper() {
		...
		synchronized(this) {
			while(isAlive() && mLooper == null) {
				wait();	//        Looper  
			}
		}
	}
	public void run() {	
		...
		Looper.prepare();	//   Looper  
		synchronized (this) {
			mLooper = Looper.myLooper();
			notifyAll();	//     Looper   ,Looper     
		}
		....
		Looper.prepare();	//     
	}
}

 
次の章では、MessageQueueを分析します.メッセージはどのようにメッセージキューに送信されますか?Looperは、MessageQueueからメッセージを取得する方法、すなわちMessageQueueである.next()は具体的にどのように実現されていますか?