Handler机制
Hanlder作用
- handler是更新UI界面的机制(线程间的信息传递),也是消息处理机制,可以用来发送和处理消息
Handler的使用
Handler handelr = new Handler(){
@Override
public void handleMessage(final Message msg) {
//这里接受并处理消息
}
};
实例一个Handler对象,并重写handlerMessage()方法,然后再调用他的send和post系列的方法,还支持延迟消息
Handler分析
我们可以看下创建Handler的源码:
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Looper
从这里我们可以看到创建Handler的时候,Hanlder都会先去检查Looper是否为空。如果为空的话则会抛出异常。所以在创建Handler之前必须要先创建Looper
不过在平常创建Handler的时候,通常没有创建Looper。在使用的时候也没看见有异常,这个是因为主线程已经帮我们创建了Looper。在后面会说到。
创建一个完整的Handler是这样的:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
//开始循环取出消息
Looper.loop();
}
}
Looper.prepare();
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));
}
Looper提供Looper.prepare();来创建Looper,并且通过ThreadLocal来与当前的线程进行绑定
Looper.loop();
/**
* 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();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
//...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
//...
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//...
msg.recycleUnchecked();
}
}
可以看出Looper.loop()是个死循环,不停的通过queue.next()获取消息,并通过msg.target.dispatchMessage(msg)将消息回调到Handler,msg.target就是消息的Handler对象。
queue.next()是MessageQueue中获取Message的方法。
MessageQueue
我们都知道发送消息是通过Handler的send以及post系类的方法。但是我们一步步往下看不难发现。其实都是执行了MessageQueue的enqueueMessage(Message msg, long when);方法。
从以上可以看出,MessageQueue是负责Message消息的管理以及处理
Handler图解
线程的切换
通常会被问到Handler是怎样实现线程切换的,其实将其中的方法走向列出来,就很容易发现啦。
- 异步线程调用主线中Hander的send或者post方法
- MessageQueue收到消息,并存起来
- Looper.loop()查询消息
- MessageQueue.next();查询消息
- Message.target.dispatchMessage()将查询的消息发送出去
- 消息回到Handler.handleMessage()。
看到这里就发现消息回到主线程了,看到这里发现Handler.handleMessage()所在的线程最终还是由Looper.loop() 的线程所决定。
前面说到我们平时写Handler时并没有创建Looper。其实是我们的UI线程已经帮我们创建了。在创建Activity的时候就已经帮创建了一个主线程。
了解更多的关于Android主线程(ActivityThread)
Message的创建
Android给message设置了回收机制,在创建Message的时候尽量复用,减少内存的消耗。
可以Message.obtain()以及handler.obtainMessage()来获取Message对象
总结
MessageQueue 就是设计模式中的缓冲区,它扶着接收生产这发送过劳的数据先进先出的队列心事,保存所有消息。在UI线程Lopper不断的从MessageQueue取出消息执行
Looper的主要任务就是维护MessageQueue中的消息队列,它负责取出要处理的消息任务,先判断Looper是否为空,如果不为空就一直循环不断冲MessageQueue中取出消息,然后通过dispatchMessage派发出去处理
Handler负责发送以及处理消息
每个线程只能有一个Looper对象,而且是通过ThreadLocal来存放,其他线程无法访问当前的Looper。
Looper可以让一个普通的线程具有消息循环的能力。
说UI线程都默认有一个Looper对象,可以通过Looper.myLooper()获取到
在一个Looper对象可以有多个Handler
小弟能力有限,有不足之处还望指出。