handler消息处理源码学习

来源:互联网 时间:1970-01-01

网上已经有很多handler类学习的文章了,譬如鸿洋大神的文章就写的很好,但是我认为自己进行android源码的学习是每个android开发所必须学会的,不能总是查看网上的大神的解析,自己还是需要尝试,这样才能更好的了解android的相关运作的过程。

首先介绍一下handler类吧,为什么会有handler的产生?
当我们在UI线程中进行一些耗时操作的时候,我们就会想到去开辟一个新的线程进行数据的获取或者推送,进而在数据操作完成的过程后进行UI界面的刷新,这是我们的思路,但是由于安卓是单线程模型,所以我们根本不可能在一个子线程中进行UI界面的更新,所以这时候就有了handler类的由来,我们经常如下使用handler类:

 private Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { //这里进行更新UI操作 super.handleMessage(msg); } };new Thread(new Runnable() { @Override public void run() { //这里进行耗时操作 //通知界面更新 Message message=handler.obtainMessage(); message.obj="要传递的参数"; //返回给handler message.sendToTarget(); } }).start();

上述是一个最基本的handler操作,当然也有handler.post()方法等,这里就不详细叙述了。
下面我们站在源码的角度来尝试解析一下内容:
首先查看一下handler的构造方法

 public Handler() { this(null, false); } public Handler(Callback callback) { this(callback, false); } public Handler(Looper looper) { this(looper, null, false); } public Handler(Looper looper, Callback callback) { this(looper, callback, false); } public Handler(boolean async) { this(null, async); }

我们可以看到,构造方法中都是调用了本类的另一个构造方法,我们再点击进去查看

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(); 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; }

在其中我们可以看到mLooper=Looper.myLooper()这句话,他是做什么的呢,我们继续点开查看发现在Looper实现了这个方法

 public static Looper myLooper() { return sThreadLocal.get(); }

发现这个方法是用来获取当前线程所关联的looper,那么从这点中我们可以看出来,handler类的工作是要配合着looper进行的。我们再往下看发现mQueue = mLooper.mQueue,干嘛用的呢,我们继续查看发现这是looper中的一个变量,我们查看源码会发现到在looper的构造方法中实例化了这个变量

private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }

原来他的名字叫做消息队列,顾名思义是拿来存放消息数据的。

从上文来看,handler类的初始化伴随着looper还有mQueue的初始化。

接下来我们查看handler中的sendMessage方法:
阅读源码你会发现handler中所有的sendMessage系列的方法最终会调用到handler中的sendMessageAtTime方法:

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将消息发到哪里去了呢,肯定就是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.sendMessage方法后,handler将message传进了消息队列中,即我们上文所讲的mQueue中,在此handler类发送消息完毕。
那么疑问来了,我们将消息发送后,如何在handler的handlerMessage获取消息并且进行处理呢?这时候就必须讲到Looper这个核心类了,在前面我们讲过,handler的初始化是跟looper和MessageQueue紧紧相连的,所以我们有必要学习一下looper。
在looper中,最重要的就是两个方法,loop()方法和prepare()方法,下面我们一一的去认识他们:
prepare():

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)); }

我们在其中可以看到,prepare方法中新建了一个Looper对象,并且把它存储在sThreadLocal中,sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量。这也就让handler在调用looper.myLooper时候获取到了looper对象,同时我们还可以注意到,prepare方法只能调用一次,如果调用两次以上,就会抛出异常,这也间接证明了一个线程对象中只能有一个looper。

loop():

 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; // 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(); } }

在此方法中写了一个死循环的操作,进行的是Message的相关处理,不断地从消息队列(mQueue)进行消息的取出,然后调用msg.target.dispatchMessage(msg)方法将消息分发出去,msg.target指向的是与当前Looper进行关联的handler对象,也就是说消息再次回传给handler,这就完成了消息回传的处理,会看一下我们最初写的handler处理过程里面
Message message=handler.obtainMessage()

handler源码

 public final Message obtainMessage() { return Message.obtain(this); }

meassage源码

public static Message obtain(Handler h) { Message m = obtain(); m.target = h; return m; }

我们看到handler和message进行了相互的关联,所以最终调用了handler的dispatchMessage方法,从名字上我们就可以知道,他进行的是消息分发的处理,我们再看一下handler源码:

 */ public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }

在里面,我们看到了熟悉的代码,即:handleMessage(msg),他是一个空方法:

 /** * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { }

我们通过重写此方法进行UI界面的更新,最终完成的UI线程与主线程的消息交互的功能,在此,解析就全部结束了。

总结一下:
handler消息分发的过程,首先我们实例化一个handler类,handler在构造方法中通过
mLooper = Looper.myLooper();
mQueue = mLooper.mQueue;
会获得一个Looper和一个消息队列,然后调用handler的sendMessage方法,sendMessage方法最终都是调用sendMessageAtTime()将消息写入Looper的消息队列当中,在此消息传递过程结束。
在looper的内部会调用prepare方法进行Looper的实例化操作,并且将Looper对象写入到sThreadLocal中(注意,UI线程中已经实现了looper对象的实例化),所以handler才能在Looper.myLooper()获取Looper对象,然后在looper.loop方法中进行消息队列中的message的分发,每分发一个message就传递回所关联的handler对象当中,即调用handler的dispatch方法,最终调用handleMessage完成消息处理的全部过程。


相关阅读:
Top