1. 在做移动端开发时对handler都不会陌生,之前看过handler发送消息和传递消息的源码,但是时间久了仅有印象,一直想形成书面文字,加深自己的理解,现在可以了。
2. 我们在使用handler的时候,一般有如下用法:
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d(TAG, "handleMessage: ");
}
};
Message msg = handler.obtainMessage();
msg.what = 1;
handler.sendMessage(msg);
或
handler.post(new Runnable() {
@Override
public void run() {
Log.d(TAG, "run: ");
}
});
注:但是内部的处理流程归根结底都是同一个流程
3. 我们先说一下在子线程中创建使用Handler的场景,这种情况相对于在主线程中创建使用稍微繁琐些,因为需要自己创建looper和开启消息队列的循环(其实就两个方法)
1. 线程中创建使用方法(示例代码仅仅是说明问题,不考虑使用性):
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Handler workHandler = new Handler();
Looper.loop();
}
}).start();
注:可以总结以下:
i. 调用Looper.prepare(),创建该work线程的loop对象(源码如下):
public static void prepare() {
prepare(true);
}
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));
}
ii. 创建handler,关联到当前线程的looper和当前线程looper对应的消息队列(源码如下):
public Handler() {
this(null, false);
}
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());
}
}
// 将此Handler和该线程的Looper关联在一起
mLooper = Looper.myLooper();
if (mLooper == null) {
//此处可以看出在创建handler的时候为什么要先创建Looper,否则无法创建成功
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
iii. 开启消息队列(源码如下):
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;
}
......(省略非关键代码)
//处理对应的消息,此处的msg.target即是对应的handler
try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
}
2. 在子线程中使用handler:
Message msg = handler.obtainMessage();
msg.what = 1;
handler.sendMessage(msg);
下面我们使用源码解析在调用了handler.sendMessage(msg)之后,底层是怎么把消息中转给我们handler的handleMessage方法执行的:
i. 先看sendMessage(msg)的原码解析:
第一步(Handler.class):
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
第二步(Handler.class):
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
第三步(Handler.class):
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
第四步(Handler.class):
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//此处将handler对象使用msg的target对象承载,后面消息队列循环处理的时候会取出对应消息的hadler
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
第五步(Looper.class):就是上面我们调用Looper.loop()之后开启的消息队列取出此消息,取出此消息target对应的handler
第六部(Handler.class):
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
注:第六步handler在分发消息的时候可以看到,在调用我们创建handler时重写的handleMessage(msg)方法之前,会有两个高优先级的先尝试消耗消息:
- msg.callback:我们先看看这个callback是什么,这涉及到handler的另外一个用法,post(Runnable),不调用此方法时此值为空:
handler.post(new Runnable() {
@Override
public void run() {
Log.d(TAG, "run: ");
}
});
【Handler.class】
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
//此处可以看出,这个callBack就是我们使用post方法时传入的runnable
m.callback = r;
return m;
}
private static void handleCallback(Message message) {
//最终回调我们传入runnable的run方法
message.callback.run();
}
- mCallback != null,这个handler是什么呢,我们看一下在handler创建的时候:
public Handler(Callback callback, boolean async) {
。。。。。。
mQueue = mLooper.mQueue;
//此处可以看出mCallback是我们创建handler的时候传入的值
mCallback = callback;
mAsynchronous = async;
}
此种使用方法较少,示例如下:
private Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.d(TAG, "handleMessage: Callback");
//此处返回false时才会调用我们创建无参数Handler构造方法时的handlerMessage方法
return false;
}
})
以上总结如下,如果创建handler的时候传入了callBack,同时重写了handlerMessage方法,也调用了post(Runnable),优先级由高到低是:post(Runnable),callBack,重写的handlerMessage
4. 在主线程中创建和使用Handler相对比较简单,因为Looper的创建和消息队列的开启系统已经在应用程序的main函数中给我们做好了:
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
AndroidKeyStoreProvider.install();
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
//此处创建主线程的Looper
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
5412 LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//此处开启消息队列的循环
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
5. Handler使用总结:
- 一个线程Thread(无论UI线程还是工作线程)仅有一个Looper,一个Looper有一个MessageQueue,UI线程Looper的创建和关联消息队列的循环开启在应用启动时系统已经帮我们初始化完成,但是work线程需要我们自己初始化。
- 使用handler时(无论是sendMessage还是post(Runnable))消息在哪个线程执行取决于handler创建时关联的是哪个looper
- handler处理消息的优先级
- 实际开发过程中,有时候会发现在子线程中创建对象会报错提示创建Handler之前先调用Looper.loop(),很大可能是此对象初始化时有handler的创建操作,而你是在子线程操作,所以会遇到此问题。