Android规定访问UI只能在主线程中进行,如果在子线程中访问UI,程序就会抛出异常:throw new CalledFromWrongThreadException.
Only the original thread that created a view hierarchy can touch its views。
相信大家开发中都会遇到过,所以更新UI的操作必须在主线程,但是android建议不要在ActivityThread中进行耗时操作,否则会导致程序ANR.考虑一种情况,如果我们从服务器拉取信息并将其显示在UI上,这个时候必须在子线程中进行拉取,拉取后又不能在子线程中直接访问UI,因此,系统提供Handler,就是为了解决在子线程无法更新UI的问题。系统为什么不允许子线程访问UI呢?因为Android的UI控件是线程不安全的。如果在多线程并发访问可能会导致UI控件处于不可预期状态。我们可以采用加锁机制,但是加锁是有缺点的,加上锁机制会让UI访问逻辑变得复杂,锁机制会降低UI访问效率,因为锁机制会阻塞某些线程执行。鉴于这个缺点所以不推荐使用。最简单高效的方法就是采用单线程模型来处理UI操作。
Handler工作原理:Handler在创建时会使用当前线程的Looper来构建内部的消息循环系统,如果当前线程没有Looper就会报错。
Handler的工作主要包含消息的发送与接收,发送消息通过post以及send的一系列方法来实现,post的一系列方法最终通过send方法来实现。
发送一条消息的典型过程*
public final boolean senMessage(Message msg){
return sendMessageDelayed(msg,0);
}
----------
public final boolean senMessageDelayed(Message msg,long delayMillis){
if(delayMillis < 0){
delayMillis = 0;
}
return sendMessageAtTime(msg,SystemClock.uptimeMillis() + delayMillis);
}
----------
public boolean sendMessageAtTime(Message msg, long uptimeMillis){
if(queue == null){
RuntimeException re = new RuntimeException(
this + "sendMessageAtTime() called with mo mQueue"
);
return false;
}
return enqueueMessage(queue,msg,uptimeMillis);
}
----------
private boolean enqueueMessage(MessageQueue queue ,Message msg, long uptimeMillis){
msg.target = this;
if (mAsynchronous){
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg,uptimeMillis);
}
Handler发送消息的过程仅仅向消息队列插入消息,MessageQueue的next方法就会返回这条消息给Looper,looper收到消息后就开始处理了。最终消息由looper交给Handler处理。
Handler处理消息过程:首先会检查Message的callback是否为null,不为null就通过handlerCallback来处理消息。Message的callback是一个Runnable对象,实际上就是Handler的post方法所传递Runnable参数。handlerCallback的逻辑很简单
private static void handCallback(Message msg){
message.callback.run();
}
其次检查mCallback是否为null,不为null就会调用mCallback的handleMessage方法处理消息。Callback是个Interface。
通过Callback可以采用如下方式来创建Handler对象,
Handler handler = new Handler(callback).
那么Callback有什么意义呢?他可以用来创建一个Handler的实例但并不需要派生Handler的子类,在开发中最常见的方式就是派生一个Handler子类并重写handleMessage方法来处理具体的消息。而Callback给我们提供了另一种使用Handler方式,我们不想派生子类时就可以采用Callback来实现。
Handler还有一个特殊的构造方法,通过一个特定的Looper来构造Handler,它的实现方式
public Handler(Looper looper){
this(looper, null, false);
}
通过这个构造方法可以实现一些特殊的功能。
Handler的默认构造方法:
public Handler( ){
}
这个构造方法会调用下面的构造方法。很明显当线程没有Looper的话,就会抛出“Can’t create handler inside thread that has not called Looper.prepare()” 这个异常,这也解释了在没有Looper的子线程创建Handler会引发程序异常的原因。
最后谈谈主线程的消息循环:
主线程(ActivityThread)的入口main,在main方法中系统会通过Looper.prepareMainLooper()来创建主线程的Looper以及MessageQueue,并通过Looper.loop(),开启主线程的消息循环。
ActivityThread被创建的时候就会初始化Looper,这也是主线程默认使用Handler的原因。
后面会补充:
消息队列的工作原理:
Looper的工作原理:
ThreadLocal的工作原理(平时开发很少用到,但是在特殊场景下,通过它可以轻松是实现一些很复杂的功能)