记早年的一次面试:
面试官:说说你对Handler的了解?
我:new 一个handler,然后在某个线程里发送message,在handler的handleMessage里接收message,message不要new 用Message.obtain()获取池子里的,来避免新建。
面试官:就这么多了么?
我:。。。。。。。。。。。。。。。。。
以前我对handler的理解很薄,在开发多年,深入了解多年后,细细的了解了handler
一、Looper
looper是关联message与handler的重要部分。
你在Android的子线程中new handler为啥报错,和looper关系不浅,据如下个例子,在子线程中调用handler
new Thread(new Runnable() { public void run() { Looper.prepare(); Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show(); } }; handler.sendEmptyMessage(1); Looper.loop(); }; }).start();
image.gif
或者在子线程直接使用Looper.getMainLooper();
new Thread(new Runnable() { public void run() { Handler handler = new Handler(Looper.getMainLooper()){ @Override public void handleMessage(Message msg) { Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show(); } }; handler.sendEmptyMessage(1); }; }).start();
image.gif
Looper.getMainLooper()实际就是主线程的looper,主线程默认都会创建looper
创建looper时会创建messagequeue
注:每一个线程只能有一个looper,looper是线程持有
Looper实际上是给当前子线程建立的looper,为了能够遍历当前子线程的消息队列,
源码
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 final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } 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); } } if (slowDispatchThresholdMs > 0) { final long time = end - start; if (time > slowDispatchThresholdMs) { Slog.w(TAG, "Dispatch took " + time + "ms on " + Thread.currentThread().getName() + ", h=" + msg.target + " cb=" + msg.callback + " msg=" + msg.what); } } 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(); } }
image.gif
二、MessageQueue
MessageQueue是一个消息队列,用于存放message,looper来把其中的message发送到handlermessage
采用先进先出的方式来管理message,内部采用单链表来进行维护,插入删除比较快
三、Message
就是咱最常用的消息了,按照我上面的说法建议使用Message.obtain()来获取Message实例,应为message有个pool
源码
public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); }
作者:王二蛋和他的狗
链接:https://www.jianshu.com/p/4b794294687b