Handler源码原理分析
来源:互联网 发布:倍福plc编程语言 编辑:程序博客网 时间:2024/05/16 16:18
Android 系统内部是消息机制,什么意思?
说说Handler运行机制?
Handler功能定义:各线程互相通讯用的。常用子线程在做完某事之后然后去更新UI之类。当然两个子线程也能用Handler相互通讯。
本文主要分析两个线程是怎么通信的?通过源码分析原理是什么?
子与主线程通讯用法:
Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch(msg.what){ case 100: String s = msg.what+" arg1="+msg.arg1+" arg2="+msg.arg2+" obj="+msg.obj; mTextView.setText(s); Logger.d(s); break; default: break; } } };.... new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); mHandler.sendEmptyMessage(100); } catch (InterruptedException e) { e.printStackTrace(); } } }).start();
子与子线程通讯用法:
new Thread("thread2"){ public void run() { Looper.prepare(); mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); String s = msg.what+" arg1="+msg.arg1+" arg2="+msg.arg2+" obj="+msg.obj; Logger.d(s); } }; Looper.loop(); } }.start();
发送时不变,还是用handler对象直接发送空消息,或者创建消息发送。
就多了Looper.prepare()
和Looper.loop();
等下会讲为什么。
需要分析的类
Message:消息对象,用到存放数据,和下一个Message对象
MessageQueue:字面意思消息队列,但其实它并不是队列,不过确实是负责消息的插入和取出
Handler:给用户层用来创建和发送消息,和处理收到的消息
Looper:不断循环取消息,和调用Handler处理消息
(说实话,这种看别人简单的总结根本不能理解,肯定想问,这到底是Handler发送处理消息,还是Looper发送处理消息?等等疑问。这都个人理解,还是看源码说吧)
先来看传递的对象Message,有几个常用属性。
**Message.class** public int what; //区分消息的标识,在发送消息和接收时确认 public int arg1,arg2; //可以传递两个int值 public Object obj; //其它想要传递的对象
然后直接进Handler 类 mHandler.sendEmptyMessage(100);
看看发送时做了什么。
**Handler.class**public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg,0);}...//延迟多少毫秒发送public final boolean sendMessageDelayed(Message msg,long delayMillis){ if(delayMillis< 0){ delayMillis=0; }// SystemClock.uptimeMillis()系统开机时间 return sendMessageAtTime(msg,SystemClock.uptimeMillis()+delayMillis);}//在一个准确时间发送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); }
可以看到,不管是sendMessage
,还是sendMessageDelayed
等……最后都是调用了sendMessageAtTime
,然后enqueueMessage
,又分发给了queue.enqueueMessage(msg, uptimeMillis)
,然后发现有个MessageQueue queue
,看在哪赋值?在Handler构造函数中,Handler构造函数也很多,最终进:
**Handler.class**public Handler(Callback callback, boolean async) { ... 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; }
观察到mQueue是从Looper中拿来的,如果Looper为空,就throw new RuntimeException()
,那进Looper.myLooper();
**Looper.class** public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
看sThreadLocal赋值
**Looper.class** // sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
直接在初始化就定义了,并且static final,说明一个进程只有一个,并无再赋值,然后看ThreadLocal是什么?
ThreadLocal 定义:与线程想关的数据存储类。
ThreadLocal 使用
ThreadLocal<Boolean> mThreadLocal=new ThreadLocal<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); mThreadLocal.set(true); Logger.d(Thread.currentThread() + " " + mThreadLocal.get()); new Thread(new Runnable() { @Override public void run() { Logger.d(Thread.currentThread() + " " + mThreadLocal.get()); mThreadLocal.set(false); Logger.d(Thread.currentThread() + " " + mThreadLocal.get()); } }).start(); }**log**D/: Thread[main,5,main] trueD/: Thread[Thread-221,5,main] nullD/: Thread[Thread-221,5,main] false
用法简单。只有get、set、remove。可以看到,主线程set(true),get()是true。在子线程中,第一次get,因为没有set,直接为null。然后set(false),取出false,说明在子线程中,并没有get到主线程set的值。看看实现:
**ThreadLocal.class**public class ThreadLocal<T> { public T get() { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values != null) { Object[] table = values.table; int index = hash & values.mask; if (this.reference == table[index]) { return (T) table[index + 1]; } } else { values = initializeValues(currentThread); } return (T) values.getAfterMiss(this); } public void set(T value) { Thread currentThread = Thread.currentThread(); Values values = values(currentThread); if (values == null) { values = initializeValues(currentThread); } values.put(this, value); } ... Values values(Thread current) { return current.localValues; } static class Values { private Object[] table; }}
Values 为ThreadLocal 的静态内部类,可以看到,数据最终存储的地方在Thread对象本身里的localValues.table数组里,ThreadLocal只是判断线程,然后把数据有序在放在table里,这里用了一个高效存储算法,table[i]为key,[i+1]为value,大概就是这样意思,这样可能效率性能会好吧!
如果Thread对象本身Values存储怎么办?实现这个和线程相关的存储数据有很多方法,自己也可以实现,下面自己实现一个:
//自己写的ThreadLocalpublic class ThreadLocal<V> { private Map<Long,V> mMap; public ThreadLocal() { mMap = new HashMap<>(); } public V get(){ long id = Thread.currentThread().getId(); return mMap.get(id); } public void put(V value){ long id = Thread.currentThread().getId(); mMap.put(id,value); }}
用线程唯一标识为Key就行,效率可能没google写的ThreadLocal好。
再回到Looper.myLooper()方法。
**Looper.class**public static @Nullable Looper myLooper() { return sThreadLocal.get();}
这里线程取到的肯定为空,唯一赋值方法在
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));}
所以我们在子线程初始化Handler时,才要Looper.prepare();
为了实例化Looper,而且每个线程还只能调用一次,那我们的主线程在那调用的呢?那就要到ActivityThread.class看看了,ActivityThread就是每个应用的大门,应用的main函数。activity、service、broadcasts等都是在这里启动。
public final class ActivityThread { ... public static void main(String[] args) { ...省略代码若干 Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } ... Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); } final Handler getHandler() { return mH; }}
可以看到,有熟悉的java的main,new Handler()
之前调用Looper.prepareMainLooper();
这个内部也是prepare()
,而且这个Handler处理这个应用系统所有Message,Activity生命周期、createService等都是这个handler进行分发。这个类以后要好好研究,所以为什么这就是android系统内部的消息机制,无论点击按钮,启动页面,都是通过Handler进行发送消息然后分发到各个类处理。
Ok,创建了Looper,创建了MessageQueue
,然后看MessageQueue
的enqueueMessage
方法
boolean enqueueMessage(Message msg, long when) { ... synchronized (this) { ... msg.markInUse(); msg.when = when; Message p = mMessages;//单链表的第一个message boolean needWake;//是否需要唤醒,如果链表中没有待处理的message,主线程将睡眠 if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked;//上一个message为空,说明这是要处理message队列的第一个,将唤醒主线程,这里会为true } else { needWake = mBlocked && p.target == null && msg.isAsynchronous(); //这一段逻辑是取出链表中的最后一个Message prev,把新的msg赋值给它的next Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr);//为true,将唤醒主线程 } } return true;}
这里可以看到,当前msg是赋值给最后一个msg的next,这里像是单链表。如图:
Message mMessages;即是链表第一个msg,也就是最快将要处理的msg(如果不为空的话)
这里有两种情况,else表示链表不为空,通过for循环,定位到最后一个msg,然后把新传递进来的msg赋值给最后一个msg的next。这就算是添加成功了。if表示链表为空(如果你进入一个新页面,不做任何操作,msg队列将会被处理完,然后主线程会睡眠,当有新的msg进来时,要唤醒主线程) nativeWake(mPtr);
是个native方法,唤醒主线程。
到此,msg就算是添加到队列中了,然后在哪里处理呢?
这就要看ActivityThread中main方法最后调用了Looper.loop();
因为这个会阻塞线程,所以要放在线程最后调用。
public static void loop() { final Looper me = myLooper(); ... final MessageQueue queue = me.mQueue; ... for (;;) { Message msg = queue.next(); // might block if (msg == null) { return; } 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); } ... } }
简单理解就是循环从MessageQueue
中next();
方法取msg,为空将结束循环,否则msg.target.dispatchMessage(msg);
这里msg.target
就是创建msg时的handler,进 dispatchMessage
方法。
**Handler.class** public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
如果msg有callback
,这个callback是Runnable
,否则检查mCallback
不为空,调用mCallback.handleMessage(msg)
,最后调用自身的handleMessage(msg);
,我们一般都是直接new Handler()
,重写handleMessage(msg)
方法。可以看见传递callback
也是可以的。这里比较简单。
然后重点看queue.next()
,也就是取出msg方法
**MessageQueue.class** Message next() { int nextPollTimeoutMillis = 0; for (; ; ) { ... nativePollOnce(ptr, nextPollTimeoutMillis); ... synchronized (this) { // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; ... if (msg != null) { // Got a message. mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; msg.markInUse(); return msg; } else { // No more messages. nextPollTimeoutMillis = -1; } ... } } }
大致为mMessages
是否为空,不为空就把return mMessages
出去,并且next
标记清掉,给mMessages = msg.next;
赋于下一个msg。为空的话nextPollTimeoutMillis = -1;
下次循环中, nativePollOnce(ptr, nextPollTimeoutMillis);
为-1时将睡眠。
而且我们还发现Printer logging = me.mLogging;
会调用Printer.println(String n)
,说明我们可以监听到msg的处理,例:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { Looper.myLooper().setMessageLogging(new Printer(){ @Override public void println(String x) { Log.d("TAG",x); } }); Looper.myLooper().getQueue().addIdleHandler(new MessageQueue.IdleHandler() { @Override public boolean queueIdle() {//消息队列处理完毕回调,return false 将只能监听一次结束 return true; } }); }
addIdleHandler
可以监听消息队列处理完毕,setMessageLogging
可以监听消息处理前后,打打log:
D/: >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82f: 0D/: <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82fD/: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$PerformClick@c098179: 0D/: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$PerformClick@c098179D/: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$UnsetPressedState@c36fb1f: 0D/: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$UnsetPressedState@c36fb1fD/: >>>>> Dispatching to Handler (android.app.ActivityThread$H) {b0be8e6} null: 101D/: <<<<< Finished to Handler (android.app.ActivityThread$H) {b0be8e6} nullD/: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} null: 6D/: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} nullD/: >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82f: 0D/: <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82fD/: >>>>> Dispatching to Handler (android.app.ActivityThread$H) {b0be8e6} null: 100
总结: Handler
消息机制就是,主线程不断循环(Looper.loop
)检查有无待处理msg(queue.next
),有就处理(handler.dispatchMessage()
),没有就睡眠(nativePollOnce()
)。当子线程发送了一个msg时(queue.enqueueMessage
),唤醒主线程(nativeWake()
),主线程就接着处理(queue.next
),从而实现了子线程与主线程通信。原理也就是子线程与主线程共同操作一个队列,一存,一取。原理简单粗暴,不过nativePollOnce
睡眠、nativeWake
唤醒、两个为native方法,肯定不是sleep那么简单。
- Handler源码分析原理
- Handler源码原理分析
- handler机制原理源码分析
- Handler原理讲解及源码分析
- Android 5.0 源码分析 Handler Looper MessageQueue 底层原理
- Android源码分析--Handler机制的实现与工作原理
- 最简洁的Handler、Looper、Message源码级原理分析
- Handler,Looper 原理分析
- Handler原理分析
- Android Handler原理分析
- Handler原理分析
- Handler原理分析
- handler的原理分析
- Handler 源码分析
- Handler的源码分析
- Looper、Handler源码分析
- Handler源码分析
- [Android源码]Handler分析
- Ubuntu安装scrapy
- Linux平台安装opencv3.1.0
- 如何在SpringBoot中监控执行引擎(actuator)?
- PHP邮件发送代码实现
- Leetcode 714
- Handler源码原理分析
- Choosing Capital for Treeland (树形dp)
- LeetCode-Split Linked List in Parts
- [LeetCode] Best Time to Buy and Sell Stock
- 为什么java函数不支持参数默认值?
- angular2
- 在列表中找出两个彼此最接近但不相等的数
- 使用Java实现最大堆
- 九、Docker-compose