牛骨文教育服务平台(让学习变的简单)

Android系统中消息处理

原理:

Android系统中每个线程可以拥有唯一一个Looper实例,在Looper的构造函数中创建一个唯一的消息队列MessageQueue,即MessageQueue对于线程来说也是唯一的。而Android应用在启动的时候默认会为主线程创建一个Looper实例,称为MainLooper,并借助里相关的Handler和Looper里面的MessageQueue完成对Activity、Service、BroadcastReceiver等组件进行管理。而在子线程中,Looper需要显示调用Looper.Prepare()创建实例。Prepare()通过ThreadLocal来保证这个Thread内只有一个Looper实例。
   

Handler在创建的时候可以显示指定Looper,这样在Handler在调用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(Callback 实现了Runnable接口),则调用其run()函数进行消息的进行处理

2) 如果设置了Handler里面mCallback(实现了Callback接口的handleMessage),则由handleMessage()进行处理

3) 最后才由继承于Handler并实现了其handleMessage()方法的子类通过这个handleMessage()来处理

Message:

消息,就是线程间通信的数据单元,里面可以封装各种信息,Android系统中消息是通过Message类来封装的。Message这个类实现了Parcelable接口,所以可以通过Intent或IPC传递。定义了一个能够发送给Handler对象的消息,包含了消息的描述和任意数据对象。主要包含两个int类型字段和一个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对象给该消息队列,并在消息队列出口处理它们。
两个主要作用: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()具体是怎么实现的?