前言
在Android中,只有主线程才能更新UI,但是主线程不能进行耗时操作,否则会产生ANR异常,所以常常把耗时操作放到其他子线程进行。如果在子线程中需要更新UI,一般都是通过Handler发送消息,主线接收消息后进行相应的UI逻辑处理。
一.什么是Handler
Handler是一个消息分发对象。
Handler是Android系统提供的一套用来更新UI的机制,也是一套消息处理机制,可以通过Handler发消息,也可以通过Handler处理消息。
二.为什么使用Handler
为了解决多线程并发的问题!
比如:如果在一个activity中有多个线程同时更新UI,并且没有加锁,就会出现界面错乱的问题。但是如果对这些更新UI的操作都加锁处理,又会导致性能下降。出于对性能问题的考虑,Android提供这一套使用Handler更新UI的机制,不用再去关心多线程的问题,所有的更新UI的操作,都是在主线程的消息队列中去轮询处理的。
在Android系统中,只有主线程才能更新UI,提到主线程,就不得说一下ActivityThread,一个应用内部的逻辑处理都是在ActivityThread内部依靠Handler来进行处理的,比如:activity、service相关的创建等相关逻辑,在应用创建后,会调用到ActivityThread内部的main()方法,逻辑如下:
public static void main(String[] args) {
......
//创建Looper
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
//创建Handler
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
//开启loop()循环
Looper.loop();
}
从上面可以看到在ActivityThread里面的main()中,执行了Looper.prepareMainLooper()及Looper.loop(),接下来一起分析一下Android系统的消息处理机制。
三.源码分析
Android内部的消息处理机制主要是由Handler、Looper、MessageQueue、Message来组成的,具体分工如下:
Handler:负责发送消息及处理消息
Looper:不断的从消息队列中取出消息,并且将消息给发送本条消息的Handler
MessageQueue:负责存储消息
Message:消息本身,负责携带数据
1.Looper
Looper分为主线程和其他子线程,前面讲到,主线程的Looper是在进程启动后调用ActivityThread的main()里面通过prepareMainLooper()创建的:
a.prepareMainLooper()
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
prepareMainLooper()内部会调用prepare(false)来进行创建,且Looper是不能退出的,然后对sMainLooper进行赋值;
b.prepare()
//只能通过Looper.prepare()方法去初始化一个Looper
public static void prepare() {
prepare(true);
}
//一个线程中只能有一个Looper对象,否则在第二次尝试初始化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));//创建了new Looper
}
子线程通过prepare()内部调用prepare(true)来创建对应的Looper,且Looper是可以退出的,为什么要退出,后面会讲到;
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
private Looper(boolean quitAllowed) {
//创建Looper的时候会创建一个MessageQueue
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper构造方法内会创建MessageQueue(),为后续消息处理做准备,然后获取到当前的Thread赋值给mThread,后续通过getThread()可以获取到当前的thread,可以用来判断是否为主线程。