我们都知道ActivityThread是程序的入口,以下是App入口处的部分代码
// 创建主线程Looper对象
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
// 创建主线程Handler
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//开始消息循环
Looper.loop();
我们先来看主线程Looper消息循环的创建过程
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
Looper对象真正创建的地方,可以看到传递了一个quitAllowed值,重字面意思上来看是否允许退出,而prepareMainLooper方法里传递的是false, 因此主线程的Looper是不允许退出的,然后同时把创建的Looper对象跟线程的sThreadLocal绑定,同时可以看到判空处理每个线程只能持有一个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));
}
上面prepareMainLooper方法还调用了myLooper方法来给Looper赋值
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
public static @NonNull MessageQueue myQueue() {
return myLooper().mQueue;
}
// Looper 对象持有了对应线程的引用,同时内部维护了一个单链表的消息队列
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
写到这,我们简单总结下结论,一个线程只能有一个Looper对象,每个Looper对象内部只有一个单链表的消息队列(MessageQueue).
我们再来看下Handler类
// handler持有了所在Looper的引用
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
// 快捷方式获取一个跟主线程关联的Handler
/** @hide */
@NonNull
public static Handler getMain() {
if (MAIN_THREAD_HANDLER == null) {
MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper());
}
return MAIN_THREAD_HANDLER;
}
实际开发中的使用场景
1、在其他线程想操作UI
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
// 把消息发送到主线程的Looper中,因此 handlerMessage()方法也会在主线程中执行
Handler handler = new Handler(Loop.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Looper.loop();
}
}).start();
- 消息发送到当前线程的Looper中处理,因此为了方便使用,系统提供了HandlerThread类简化代码,方便开发者。
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Looper.loop();
}
}).start();
-
UI线程延时更新等
如果在主线程中通过new Handler()方式创建Handler的对象handler,那么handler对象中持有的Looper是主线程的Looper因此handler对象中持有的MessageQueue队列也是主线程的消息队列,因此handler对象发送的消息也都是发送到主线程的消息队列中了。
Q: 如何保证谁(handler)发送的消息谁来处理?
A:Handler发送消息到MessageQueue之后会把Message的target属性设置为Handler自身,正如Looper取出消息处理消息的处理一致
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
Q: 为什么在非UI线程中直接创建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());
}
}
// 获取当前线程的Looper, 如果是非UI线程默认是没有Looper对象的因此, 直接创建Handler必然会崩溃, 所以需要主动调用Looper.prepare(), Looper.loop();
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}