当前位置:文档之家› Handler消息处理机制

Handler消息处理机制

Handler消息处理机制1.概述。

Handler消息处理机制对于初学者来说,应该算是一块心病,几乎每次面试都会被问到,今天我抽时间从源码的角度总结一下相关知识点。

先看一下我们平时是怎么用的,如下代码实例:public class MainActivity extends AppCompatActivity {private TextView text;private Handler mHandler;int i=0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_main);text = (TextView) findViewById(R.id.text);mHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);text.setText("变为:"+msg.what);}};}public void sendMes(View view){mHandler.sendEmptyMessage(i);i++;}}很简单,onCreat()方法中实例化了一个Handler实例,实现其handlerMessage(Message msg)方法,在方法中改变TextView的显示内容,在布局文件中放了一个Button设置其android:onClick="sendMes",看一下效果:相信每一个开发Android的人都会使用Handler更新页面,但是我们还要知道它是如何实现的,下面我们就剖析一下它的源码吧。

2.源码解析我们都知道Handler机制涉及到了几个类,他们分别是Handler、Message、MessageQueue、Looper,先来了解一下这几个类的作用:1.Message:个人认为可以看成是我们要传递消息的载体,我们可以将信息设置到它的what属性,arg属性等。

2.MessageQueue:统一存储Message的类,我们发出的每一个消息都将保存到MessageQueue中,我们可以从里边取消息进行处理。

3.Looper:统一管理message,循环取出MessageQueue中存储的消息进行处理的类。

4.Handler:发送Message,处理Message的类。

下面我们先看一下Looper这个类,这个类有两个方法非常重要:prepare()、loop(),瞅瞅prepare()方法的实现:public static void prepare() {prepare(true);}调用了单参数的重载方法,传的是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));}在这里用到了ThreadLocal类,这个类为每一个用到它的线程提供一个副本,每一个线程只能访问自己的数据。

判断不为空保证了我们这个方法只能被调用一次,创建了Looper实例,并将我们的true继续传递,那么我们看一下Looper 的构造函数:private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();}在Looper中创建了MessageQueue对象,并传递true,大家也行会问这个true 是干嘛的,它是后续用来判断消息循环是否可以终止的,系统在UI线程里边调用时传递的false,后边会介绍到,再看看他的MessageQueue中又做了什么呢?MessageQueue(boolean quitAllowed) {mQuitAllowed = quitAllowed;mPtr = nativeInit();}保存了传递进来的boolean值。

这样我们就看完了Looper的prepare()方法的实现流程,总结一下:创建了当前线程对应的Looper对象并保存的mThreadLocal对象中,同时创建了与之对应的MessageQueue对象。

下边看一下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 blockif (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 loggerfinal Printer logging = me.mLogging;if (logging != null) {logging.println(">>>>> Dispatching to "+ msg.target + ""+msg.callback + ": "+ msg.what);}final long traceTag = me.mTraceTag;if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {Trace.traceBegin(traceTag, msg.target.getTraceName(msg));}try {msg.target.dispatchMessage(msg);} finally {if (traceTag != 0) {Trace.traceEnd(traceTag);}}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();}}这个方法稍微长一点,但是并不难,首先调用myLooper()方法从mThreadLocal 对象中获取保存的Looper对象,并从Looper中拿到对应的MessageQueue对象,一个for循环获取queue中的每一个Message,最终调用了msg.target.dispatchMessage(msg);嗯?这个target是什么?其实就是我们实例化的mHandler对象,这里先记住,后边会说到,去Handler类中找一下dispatchMessage()方法:public void dispatchMessage(Message msg) {if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}}看到没,系统在这里调用了handlerMessage(msg)方法,看一下:public void handleMessage(Message msg) {}咦,是个空实现,没错,因为我们在实例化Handler的时候重写了handlerMessage(Message msg)方法,所以会执行到我们更新页面UI的代码。

到这,我们Looper.loop()方法也介绍完了,总结一下:通过myLooper()方法获取当前线程对应的Looper对象,并取到对应的MessageQueue,创建一个for()的无限循环,去取MessageQueue中的Message,取到message中保存的Handler 对象调用其dispatchMessage()方法,最终执行到我们的handlerMessage(Message msg)方法更新UI。

相关主题