首先Message(消息)类不用多说,内部用what(啥)属性来存放标识符,用obj(对象)来存放要携带的数据,用target(目标)来存放目标Handler。
所以需要有一个Handler(句柄)类来处理Message,方法是调用Handler类中的sendMessage(Message)方法,我之前一直觉得这个方法名的逻辑很奇怪,现在懂了,因为知道了另一个类:
MessageQueue(消息队列),在调用sendMessage之后Handler会依次调用两个不是重载但跟重载也差不多的内部方法,最后像这样
sent = queue.enqueueMessage(msg, uptimeMillis);
把Message发送(send)给内部创建的一个MessageQueue对象,同时把Message中的target属性设置为自己。
这时又要说到另一个类,Looper(循环器)。程序运行的时候安卓会在主线程里创建一个Looper,
1 /** 2 * Initialize the current thread as a looper, marking it as an 3 * application's main looper. The main looper for your application 4 * is created by the Android environment, so you should never need 5 * to call this function yourself. See also: {@link #prepare()} 6 */ 7 public static void prepareMainLooper() { 8 prepare(false); 9 synchronized (Looper.class) { 10 if (sMainLooper != null) { 11 throw new IllegalStateException("The main Looper has already been prepared."); 12 } 13 sMainLooper = myLooper(); 14 } 15 }
它以for死循环的方式不断尝试从队列中取出Message,
Message msg = queue.next();
取到了就调用这个Message中的target中存放的那个Handler的dispatchMessage(Message)方法。像这样:
msg.target.dispatchMessage(msg);
Handler用这个方法稍微进行一下判断,之后就转交给自己的handleMessage(Message)方法来处理消息,这个方法和onCreate一样是由程序员重写,由系统调用的。
剩下的就很简单了,handleMessage方法是程序员自己写的,想做点什么都行。
通常是根据Message中的what来switch一下,对于不同消息来源做出不同反应就可以啦。
那么总结一下:
明面上程序员做两件事。
首先是创建Handler,重写好方法,决定用它来做点什么;
后面的分为两种情况。
如果调用Handler的时候需要携带信息,就用Message.obtain()方法或new关键字得到Message对象,然后使用Handler对象的sendMessage(Message)方法交由Handler处理。
如果并不需要携带额外信息,只需要通知Handler有事要做,就不需要自己得到Message对象,直接使用Handler对象的sendEmptyMessage(int)方法,Handler会像这样
Message msg = Message.obtain();
msg.what = what;
自己创建一个Message对象,并用方法中传入的int值作为Message的what属性。
第一步,定义Handler。
第二步,发送消息。
这样。
PS:
如果要在主线程之外使用Handler要注意一个问题。
首先按照上面说的,消息是由Looper从队列中取出并分发的,只管自己的线程。可是主线程中使用的Looper是安卓系统创建的,用户新建线程的时候并不会自动创建一个新的Looper,所以Looper告诉你
final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); }
这个,Handler告诉你
mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); }
这个。
因此,要在新线程里创建Handler就需要调用Looper.prepare()方法来准备好一个Looper,这个方法会自动调用内部的重载方法,不需要担心。
private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
自己调用的时候参数是true,系统调用的时候是false,总之不需要在意。
Handler用来让其他线程修改UI啊,这个不用我说吧。