消息机制Handler及相关源码分析
来源:互联网 发布:sun官方java教程 pdf 编辑:程序博客网 时间:2024/05/21 09:17
一、Handler
1、工作原理:
Handler发送消息是往消息队列MessageQueue中插入一条消息,轮询器Looper会调用loop方法进行轮询,获取到消息后将该消息交给Handler处理。
2、发送消息(调用send和post的相关方法发送消息)
调用sendMessage,然后调用sendMessageDelayed,又调用了sendMessageAtTime。调用post方法,最终也是调用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);}会调用MessageQueue的enqueueMessage方法将消息放到消息队列中。Looper发现新消息,会处理。
3、接收消息
#Handler
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg);//是一个Runnable对象,实际是Handler的post传递的Runnable参数 } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); }}
4、Handler实例化
通过特定的Looper来构造Handler
public Handler(Looper looper) { this(looper, null, false);}
二、Looper:不停的从消息队列MessageQueue中查看是否有新消息。
1、创建Looper。每个线程最多只能有一个Looper对象。
(1)Looper.prepare();
#Looper
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));}
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed);//创建一个MessageQueue. mThread = Thread.currentThread();}(2)Looper.prepareMainLooper:主线程创建Looper,本质也是通过prepare方法创建
2、获取Looper
(1)Looper.getMainLooper 获取主线程的Looper
(2)Looper.myLooper()获取当前线程的Looper实例
3、退出Looper
#Looper
(1)直接退出Looper
public void quit() { mQueue.quit(false);}(2)设置一个退出标识,将消息队列的已有消息处理完毕才能安全退出。
public void quitSafely() { mQueue.quit(true);}会调用MessageQueue的quit方法通知消息队列退出,MessageQueue的next方法返回null。
退出后Handler发送的消息会失败。在子线程中创建Looper,在所有消息完成后调用quit方法来终止消息循环。
4、进行轮询
4、进行轮询
Looper.looper
public static void loop() { ..... //无限循环 for (;;) { //调用MessageQueue的next方法取值 Message msg = queue.next(); if (msg == null) { //木有消息了就跳出循环 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指发送消息的Handler,交给Handler的dispatchMessage方法 msg.target.dispatchMessage(msg); ..... }}5、数据存取
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();通过ThreadLocal可以实现Looper在线程的数据存取。
原理:Looper作用域是线程,不用线程有不用的Looper。而ThreadLocal是一个线程内部的数据存储类。可在指定线程存储数据,其他线程无法获取。
(1)ThreadLocal使用:
ThreadLocal<Boolean> mThreadLocal = new ThreadLocal<>();public void test() { Log.e(TAG, "mainThread:" + mThreadLocal.get()); //主线程 结果是false new Thread() { @Override public void run() { super.run(); mThreadLocal.set(false); Log.e(TAG, "thread1:" + mThreadLocal.get()); //线程1 结果是false } }.start(); new Thread() { @Override public void run() { super.run(); mThreadLocal.set(true); Log.e(TAG, "thread2:" + mThreadLocal.get()); //线程2 结果是true } }.start();}(2)ThreadLocal的set方法:
public void set(T value) { Thread currentThread = Thread.currentThread();//获取当前线程 Values values = values(currentThread); //Value的类型是ThreadLocal.Value if (values == null) { //value为null,进行初始化 values = initializeValues(currentThread); } values.put(this, value); //调用value的put方法存值}//内部存在obect类型的数组static class Values { private Object[] table;}(3)ThreadLocal的get方法:
public T get() { // Optimized for the fast path. Thread currentThread = Thread.currentThread(); Values values = values(currentThread); //获取当前线程value对象 if (values != null) { Object[] table = values.table; //取出value的table数组 int index = hash & values.mask; if (this.reference == table[index]) { return (T) table[index + 1]; //table的下一个位置存得值就是ThreadLocal的值 } } else { values = initializeValues(currentThread); //初始化 } return (T) values.getAfterMiss(this);}set和get都是操作的当前线程的value对象的table数组。
三、MessageQueue:
内部以单链表的形式存储数据,包含两个操作,插入enqueueMessage方法和读取next方法。
next是一个无限循环的方法,如果没消息就一直堵塞。如果有新消息到来,从消息队列中取出一条数据,并将其在队列中移除。
四、主线程的消息循环
1、主线程的入口是ActivityThread的main方法
public static void main(String[] args) { ..... //创建主线程的Looper和MessageQueue Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); //获取handler if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } // End of event ActivityThreadMain. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); //looper进行轮询 Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited");}返回的Handler是ActivityThread.H。包含了四大组件启动和停止的过程。
private class H extends Handler {}主线程的消息循环模型:
(1)ActivityThread通过内部类ApplicationThread和ActivityManagerService进行进程间通信
(2)AMS会回调ApplicationThread的Binder方法
(3)ApplicationThread向H发送消息
(4)ApplicationThread将通过H将逻辑切换到ActivityThread中执行(主线程执行)
注意:
- 一个Looper只能对应了一个MessageQueue。
- 一个线程中只有一个Looper实例,一个MessageQueue实例,
- 可以有多个Handler实例。
参考:Android开发艺术探索
0 0
- 消息机制Handler及相关源码分析
- Handler消息机制源码分析
- Android异步消息处理机制详解及源码分析 Handler
- Handler消息机制的源码分析
- Android消息机制 Handler源码分析
- Handler消息机制(深入源码分析)
- Handler消息处理机制源码分析
- [Android] 从源码分析 Handler 消息机制
- Android Handler 消息响应机制源码分析
- 【源码解读】Handler消息机制流程分析
- 菜鸟从源码分析Handler消息机制
- Android Handler消息机制源码分析
- Android Handler消息机制源码分析
- Android源码分析之Handler消息机制
- Handler消息机制的源码分析
- Handler消息处理机制---从源码分析
- Android 从源码分析Handler消息机制
- Android Handler消息机制源码分析
- yum安装phpMyAdmin
- opencv pca主成分分析
- Cannot change version of project facet Dynamic web module to 3.0解决方法
- mysql 统计表中条目数量的几种方法
- NTL库里函数的使用
- 消息机制Handler及相关源码分析
- 指针和数组(第四节 指针与数组之间的恩恩怨怨)
- [乐意黎原创]windows 10休眠唤醒后WIFI无信号的解决办法
- 面向对象多方法1
- 最全前端面试题
- 鼠标经过弹出透明遮罩层css写法
- 乐观锁和悲观锁的区别
- Android Drawable简介&CircleImageView简单实现
- virtualbox 设置桥接模式