Handler消息处理机制---从源码分析
来源:互联网 发布:java的compare 编辑:程序博客网 时间:2024/05/17 08:31
前言
android应用在启动时,默认会有一个主线程(ui线程),这个线程会关联一个消息队列,所有的操作都会被封装成消息进入消息队列交给主线程来处理,获取到的消息会放入一个死循环中,因此保证程序不会退出。那么handler和looper还有messageQueen和线程到底有什么关系呢?带着这种疑问,我们从handler的源码开始入手分析。
UI线程消息循环
ui线程的消息循环是在ActivityThread中的main方法里创建的,源码如下: public static void main(String[] args) { //...代码省略 Looper.prepareMainLooper();//创建主线程消息循环looper ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } AsyncTask.init(); Looper.loop(); throw new RuntimeException("Main thread loop uexpectedly exited"); }
我们可以看到,先调用了looper.prepareMainLooper()方法用来创建主线程的消息循环器,然后初始化主线程的handler,最后调用Looper.loop 方法开启循环,如果跳出循环则抛出异常。
Handler与Looper和消息队列的关系
我们平时在子线程执行玩耗时任务后经常用更新ui,必须在handler中执行。其实每个handler都会关联一个looper和looper中封装的消息队列,而每个looper又都会通过ThreadLocal关联一个线程,其实就相当于每个消息队列和一个线程关联,每个handler也关联一个线程。handler相当于一个消息处理器,将消息分发到消息队列,再由对应的线程从消息队列逐个取出消息来执行。那么handler是如何关联消息队列和线程的呢,我们看以下源代码:
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; }
调用默认的构造函数就会调用这个构造函数,可以看到构造函数里通过Looper.myLooper来获取Looper对象,同时关联了looper中的消息队列。
Looper与线程的关系
我们再看Looper中的源码:
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }public static @Nullable Looper myLooper() { return sThreadLocal.get(); } public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }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)); }
可以看到,在Looper的构造函数里创建了messageQueen,并通过native方法Thread.currentThread获取当前线程。在myLooper方法中通过sThreadLocal.get方法来获取looper对象,那么looper对象又是什么时候存储到sThreadLocal中的?可以看到prepare方法中,如果looper已经存在就会抛出异常,不存在就会创建一个新的looper对象,并将该对象保存在sThreadLocal中。
结合上面handler的源码,也就是说,每个handler对象的创建,必须保证预先有一个Looper对象,否则会抛出异常”Can’t create handler inside thread that has not called Looper.prepare()”。我们在主线程中之所以不需要创建looper的原因是因为系统在启动一个应用的时候通过Looper.prepareMainLooper()为我们创建了一个与主线程关联的Looper对象,并且开启了loop循环器,所以我们在handler中发送的消息能被接受并处理。而我们在子线程中如果要创建handler发送和处理消息,必须遵循如下写法:
new Thread(new Runnable() { @Override public void run() { Looper.prepare(); Handler handler = new Handler(); Looper.loop(); } }).start();
先通过Looper.prepare()方法初始化looper对象存入sThreadLocal方法中保证sThreadLocal.get不为null,这样初始化handler进入handler构造函数的时候就不会因为Looper.myLooper()方法调用sThreadLocal.get为空从而抛出异常了,最后调用Looper.loop开启循环。
那么我们在看看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;//1.获取消息队列 //...代码省略 for (;;) {//2.消息循环 Message msg = queue.next(); // 3.获取消息 if (msg == null) { return; } // This must be in a local variable, in case a UI event sets the logger //...代码省略 final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } try { msg.target.dispatchMessage(msg);//4.处理消息 } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } msg.recycleUnchecked();//5.回收消息 } }
可以看到,先通过Looper.myLooper方法获取looper对象和messageQueen对象,然后进入死循环不断地从消息队列取消息,最后处理消息的过程。
消息处理机制
我们从上面的代码中可以看到,通过msg.target.dispatchMessage(msg)来处理消息,那么msg.target又是什么呢?
public final class Message implements Parcelable {/*package*/ Bundle data; /*package*/ Handler target; /*package*/ Runnable callback; // sometimes we store linked lists of these things /*package*/ Message next;}
从源码可以看到,target也就是handler,实质是调用handler的dispatchMessage方法来分发消息。
我们继续看handler中的
public void handleMessage(Message msg) { }private static void handleCallback(Message message) { message.callback.run(); }public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
可以看到,如果msg的callback线程不为空,则会调用handlerCallback,也就是调用msg中callback线程的run方法,如果为空则会交给handlerMessage来处理。那么什么时候callback为空什么时候不为空呢?我们继续往下看:
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } 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;//将handle引用赋给msg if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
可以看到,在调用handler.post(Runnable r)时,会将Runnable包装成Message的callback,最后将包装后的message对象插入消息队列中,并且将handler的引用传递给message,这样就能在Looper.loop()中调用handler的dispatchMessage方法来进行消息的下发处理了。
sendMessage也是同样的实现,只不过没有包装的Runnable对象,所以调用该方法msg.callback==null,故这边就是交给handlerMessage来进行处理。
结语
handler会将每一个消息追加到消息队列中,通过Looper不断从消息队列中获取消息,并且调用handler的dispatchMessage分发消息,分发的消息再通过回调进行处理,这样,android就可以流畅的运转了。
- Handler消息处理机制---从源码分析
- [Android] 从源码分析 Handler 消息机制
- 菜鸟从源码分析Handler消息机制
- Android 从源码分析Handler消息机制
- Handler消息处理机制源码分析
- 从Handler+Message+Looper源码带你分析Android系统的消息处理机制
- 从Handler+Message+Looper源码带你分析Android系统的消息处理机制
- Android 从源码角度分析消息处理机制(Handler,Looper,Message)
- Android从源码分析一:Looper,Handler消息机制
- 从源码分析Android中Handler的消息传递机制
- Handler消息机制源码分析
- Android应用程序消息处理机制(Looper、Handler)源码分析
- Looper、Message、MessageQueue、Handler异步消息处理机制源码分析
- Android异步消息处理机制详解及源码分析 Handler
- Android多线程消息处理机制(三) Handler部分源码分析
- Handler异步消息处理机制的源码分析
- 异步消息处理机制之Handler源码分析篇
- 深入源码分析Handler的消息处理机制
- 微信小程序中点击View中任何位置都可以触发相应事件的解决办法
- javaseday04(数组容器,排序,进制转换)
- 百练_4085:数组去重排序
- select、poll以及epoll三组I/O复用函数的区别
- mysqli_result 类中的成员方法和属性
- Handler消息处理机制---从源码分析
- WIFI 一键配置原理-ESP8266
- Android EditText 限制输入类型数字或小数,并且小数位数限定为两位
- c++重载构造函数时应注意的几点
- windows安装memcached_服务器端
- centos7 系统上 mariadb galera 集群搭建
- HashMap的设计原理和实现分析
- 无知选了image file
- Android设计模式之一个例子让你彻底明白工厂模式(Factory Pattern)