1.Handler存在的意义
对于我们而言主要是用于刷新UI,因为子线程不能刷新UI,如果你对handler有充分的了解,还是可以用到其他地方的,鸿洋大神有篇博客是用handler加载图片的,不妨去研究一番。
2.掌握Handler一些必备知识点
要想实现子线程通知Handler刷新UI是比较简单的,你只要看下别人的写法自己就能模仿写出来,写多几次就能无脑的写出来了,我以前就是这么的无脑操作使用Handler刷新UI的。但是,知耻而后勇的我良心发现,这么无脑不行啊,决定去看下各位大神对Handler的讲解,总算有一番了解。
不扯淡,Handler、Looper、MessageQueue三个是一起工作的,以我的表达能力根本不用画图就能讲清他们之间的关系,先从三个单词了解它们,Handler是处理者的意思,MessageQueue是消息队列的意思,Looper循环的意思,他们之间的关系很简单,Handler有几个方法可以发送信息(当我们的子线程需要通知刷新UI的时候就这么做)到MessageQueue,Looper的loop()方法一直循环读取MessageQueue里面的消息,然后将消息分发给对应的Handler,一般是把信息交给Handler的HandlerMessage()方法,所以我们在HandlerMessage()处理消息(比如拿到的数据显示在对应的view上面),这是一个大概的流程,代码展示大概是如下几步:
3.从源码才能更加了解更多的细节(涉及到Handler、Looper、MessageQueue、Message的源码)
-
1.在UI线程中创建两个Handler(我们这里讲的Handler、Looper、MessageQueue都是属于UI线程的)
private Handler mHandler1 = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); LLog.d("handleMessage", "" + msg.what); } } ; private Handler mHandler2 = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); LLog.d("handleMessage", "" + msg.what); } };
-
2.在子线程中使用mHandler1和mHandler2发送消息到同一个MessageQueue(主线程始终只有一个)
new Thread() { @Override public void run() { super.run(); //在子线程中使用UI线程的Handler将想要发送的信息发送到MessageQueue中 //Looper会一直从MessageQueue拿到信息交给handleMessage(),所以我们只需要在handleMessage() //对消息进行处理即可,其实主线程只有一个MessageQueue mHandler1.sendEmptyMessage(1); mHandler2.sendEmptyMessage(2); } }.start();
为什么sendEmptyMessage()之后,消息就来到了handleMessage(Message msg)呢?
因为newHandler()和sendEmptyMessage()方法隐蔽了很多的细节,所以我们需要打开Handler的源码才能知道流程,请看源码:
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());
}
}
mLooper = Looper.myLooper(); //拿到当前线程(UI线程)的Looper()实例
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;
}
是的,看注释我们发现在这里我们拿到了一个需要的Looper实例,前面说过需要Looper的loop()方法不断的从MessageQueue中不断获取Message(消息),所以必须要有一个Looper实例,不急着看Handler的其他源码,先点进这里Looper.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();
}
Looper源码这里是拿到了当前线程的Looper实例,为什么一get就能有呢?因为主线程创建的时候已经帮我们set进去了,所以我们不用收到set进去,到底是如何set进去的?这是后就需要灵性了在当前类搜索找到sThreadLocal.set,是的,找到了:
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
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));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
最后一行看到了吧,简单粗暴直接new了一个Looper()进去,外层方法是prepare(),方法名是准备的意思,看来就是调用这个准备方法的时候就创建了一个Looper实例set进去了,Looper的构造函数里面直接创建了一个MessageQueue,MessageQueue(消息队列)是用于存放Message(消息)的,此时三个基佬都有了各自的实例了,那么就可以合作干活了。
如果你对sThreadLocal感兴趣,其实他就是一个static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();不懂自行学习,我也不太懂先
说了这么多连Looper在哪里创建的都不知道,我TM差点都忘了。对于这个UI线程的Looper实例是不用我们进行创建的,很多关于这部分知识的讲解都有讲到,Android 在进程的入口函数 ActivityThread.main()中,调用 Looper.prepareMainLooper, 为应用的主线程创建Looper,源码:
public final class ActivityThread {
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
if (activity != null) {
activity.attach(appContext, this, ..., );
public static void main(String[] args) {
// 在这儿调用 Looper.prepareMainLooper, 为应用的主线程创建Looper
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
}
}
看到注释那里,Looper.prepareMainLooper()这里创建了主线程Looper,而不是调用Looper.prepare()方法创建,其实Looper.prepareMainLooper()调用了Looper.prepare(false),最终还是调用了,看到这里的最后一行
Looper.loop()这个方法点击进去看是一直获取MessageQueue的Message的,看源码见分晓(略长,跟着注释看):
/**
* 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(); //这个方法前面讲过,就是Looper 实例,如果你忘了这个方法很正常,看多几次就OK
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; //这个是消息队列,等下就要掏空它(从里面不断获取Message)
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
//这里开始进入死循环,不断获取消息,分发消息
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
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
//这句才是关键,下面会对这句局进行分析
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
以上逻辑相当的简单,只要把msg.target.dispatchMessage(msg)这个函数流程走完就OK了,target是啥?为什么它有dispatchMessage(msg)方法,灵性又发挥作用了,msg.target.dispatchMessage(msg)这里面的msg是从消息队列拿到的消息,我们知道消息最后是在Handler的方法里进行处理的,那target应该就是Handler实例了,马上去Message源码搜索target,是的,我们发现他就是Handler,源码:Handler target;,这时我们需要知道什么时候将这个target赋值的,回到最开始我们new 出一个Handler的那里,只有在那里我们才操作了Handler,我们调用了handler.sendEmptyMessage();,看这里的源码,一直跟踪下去:
/**
* Sends a Message containing only the what value.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
/**
* Sends a Message containing only the what value, to be delivered
* after the specified amount of time elapses.
* @see #sendMessageDelayed(android.os.Message, long)
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
/**
* Sends a Message containing only the what value, to be delivered
* at a specific time.
* @see #sendMessageAtTime(android.os.Message, long)
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
跟了大半天才跟踪到这行msg.target = this; 是的,我们在这里将Handler放到了Message的targe字段里面了,发了一条消息过来肯定要做个标志嘛,不然这么多消息扔到消息队列,取出来都不知道给回谁,所以我们在条消息对象标记好各自的Handler,最后取出来才能给到对应的Handler。好的,知道了targe是Handler,那么msg.target.dispatchMessage(msg);的dispatchMessage(msg)方法就是在Handler里面了,终于把消息给回老子(Handler)了.源码源码源码,看下:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
直接看else里面的,if里面的的情况需要另外分析,我们发送的这些消息会交给else处理就是了,handleMessage(msg)等你等到想分手了,经历了这么多,让我更见的了解你,以后再也不会找这么久了。
记得前面是这么写的
mHandler1.sendEmptyMessage(1);
mHandler2.sendEmptyMessage(2);
那么很自然的,下面一个输出1,一个输出2
private Handler mHandler1 = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
LLog.d("handleMessage", "" + msg.what);
}
} ;
private Handler mHandler2 = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
LLog.d("handleMessage", "" + msg.what);
}
};
第一次敲博客,如果哪里讲错或者思路有些逆天,麻烦指点下,如果你是刚接触Handler,很有可能需要多看几次才能理解。如果你完全理解了,就在子线程写个Handler,在子线程发送信息,让Handler处理信息吧。
网友评论