Android多线程消息处理机制(三) Handler部分源码分析
来源:互联网 发布:最好小额网络投资理财 编辑:程序博客网 时间:2024/05/19 23:15
此文一起来看下Handler的部分源码,不用怕很简单,有英文的地方我都翻译了。
把里面相关的方法过一眼,你瞬间会明白很多。高手就不用看了,去过你的荣华富贵花天酒地。
我一致认为,想学好某一技术,首先是了解原理和熟练使用,其次是钻研其源码,看他是怎么做的。
万万不可随便在网上搜篇文章做一个demo完事,你可知有多少文章讲多么肤浅和曲解?
曾记得以前看过一个视频教程,那讲师说:“有两个队列,一个是messageQueue,一个是threadQueue”
他把runnable都当线程理解了。
1、handler可以在构造的时候传递callback,以替换handleMessage方法处理消息。
2、在构造handler的时候,可以不传递looper,默认会取当前线程的looper。如果娶不到就挂了。也可以传递looper给他。
3、handler分发message时,先判断msg的callback是否有值,有则调用runnable的run方法,不是启动线程!否则判断handler的callback是否有值,有则让其处理消息。如果处理完成后return true,则handler的handleMessage(msg)不执行了,否则继续执行。
4、获取message,或许可以new,暂时还没分析。源码已经指出可以用obtain的方式从message pool中获取,效率高。
5、handler可以发及时或延时消息,可以移除部分或者全部的待处理消息。
由于篇幅太长,此文就只聊这么多,下文总结handler用法和讲解message、messageQueue。
把里面相关的方法过一眼,你瞬间会明白很多。高手就不用看了,去过你的荣华富贵花天酒地。
我一致认为,想学好某一技术,首先是了解原理和熟练使用,其次是钻研其源码,看他是怎么做的。
万万不可随便在网上搜篇文章做一个demo完事,你可知有多少文章讲多么肤浅和曲解?
曾记得以前看过一个视频教程,那讲师说:“有两个队列,一个是messageQueue,一个是threadQueue”
他把runnable都当线程理解了。
任何技术,官方文档和源码是最直接的证据和学习资料。源码撸起:
/** * 一个handler实例可以用来发送和处理message,也可以与一个runnable对象关联. * 每一个handler只可以与一个looper关联,一个线程最多只能有一个looper, * 一个looper内置一个唯一的messageQueue。在同一个线程中,你可以再创建一个handler, * 与同一个looper和messageQueue关联。若多个handler关联同一个looper,则发送的message都会 * 装载同一个messageQueue里面,由同一个looper管理。looper抽取出message后,会让message找 * 的妈妈。message是谁发送的,就有谁的handleMessage()方法处理。因为message.target = handler, * message持有妈妈的电话号码 */public class Handler { //Handler的成员变量 final MessageQueue mQueue;//引用所关联的looper的messageQueue final Looper mLooper;//所关联的looper final Callback mCallback;//handler有callback属性 final boolean mAsynchronous;//是否异步 IMessenger mMessenger;//.../** * 在构建Handler实例的时候提供一个CallBack接口,避免实现你自己的handler子类 * @param msg 一个message对象 * @return True 如果没必要传递,就返回true消耗处理 */ public interface Callback { public boolean handleMessage(Message msg); } /** * 子类必须实现这个方法,来接收和处理消息 */ public void handleMessage(Message msg) { } /** * 在这里处理系统消息分发 */ public void dispatchMessage(Message msg) { if (msg.callback != null) { //mssage里面有CallBack?稍后分析 handleCallback(msg); } else { if (mCallback != null) { //mCallback是Handler的回调吗?就是上面提到的接口? if (mCallback.handleMessage(msg)) { return; } }//这个就是上面提到的接收和处理消息的方法吗? handleMessage(msg); } }/** * 无参数的构造方法创建handler对象,默认关联当前线程的looper。 * 如果这个线程没有looper, 这个handler将不能接收和发送message, * 且抛出异常。 * 明白了为什么在activity创建handler不需要关联looper了吧?因为他自己关联。 * 在looper专题1章节讲解到的,Looper.prepare()之后才创建的handler,知道为什么了吧? * 我在new handler的时候传递了looper?看下一个构造方法吧。 */ public Handler() { this(null, false); }/** * 使用提供的looper对象替换handler中默认的looper, * 以免因为默认的looper为null而导致程序异常。 * @param looper 这个looper不能为空 */ public Handler(Looper looper) { this(looper, null, false); }/** * 构造一个关联当前默认线程的looper的handler对象, * 同时携带一个可以为你处理message的回调接口。不用handleMessage(Message msg)方法了?!! * 如果当前线程没有looper,那就等着作死吧 * @param callback 你可以用这个回调类处理message,你也可以不传递, * 实现handleMessage(Message msg)方法 */ public Handler(Callback callback) { this(callback, false); }/** * 同时提供looper和CallBack回调 */ public Handler(Looper looper, Callback callback) { this(looper, callback, false); }/** * 使用默认线程的looper,同时设置处理程序是否应该是异步的 * handler默认是同步的,除非特别指定是异步的。 * 此构造函数是隐藏的,我们不可以调用 */ public Handler(boolean async) { this(null, async); }/** * 使用当前默认的looper,指定的CallBack,设置是否需要异步 * Handler默认是同步的,除非调用带有此项设置的构造器。 * * 异步消息表示不需要全局排序就同步消息的中断或事件. * 异步消息不受MessageQueue#enqueueSyncBarrier(long)方法同步阻拦. * * @hide 这是一个隐藏的构造方法 */ public Handler(Callback callback, boolean async) { //返回当前线程的looper,如果当前线程没有looper,则返回null mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); }//获取looper里面的消息队列,赋值给当前handler对象。有人说他这样很无耻 mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }//这个构造方法不用多说,一看就懂public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }/** * 返回一个表示指定消息的名称的字符串. * 默认的实现将返回message的CallBack类名, * 或者返回message的what属性值的16进制表示形式. */ public String getMessageName(Message message) { if (message.callback != null) { return message.callback.getClass().getName(); } return "0x" + Integer.toHexString(message.what); }/** * 从全局的message池中返回一个全新的message对象,比创建和分配新实例更有效 * 返回的message的target属性会设置为this,即待处理对象 * 如果你不想给message的target属性赋值,可以调用Message.obtain()方法,不传参数 */ public final Message obtainMessage(){ return Message.obtain(this); }/** * 与上面重载的方法的区别,obtain的同时设置了what属性 */ public final Message obtainMessage(int what){ return Message.obtain(this, what); }/** * 又设置了一个object属性,以满足message返回任意类型数据 */public final Message obtainMessage(int what, Object obj){ return Message.obtain(this, what, obj); }/** * 参数全家福,到齐了。这些参数没有特定的含义,根据你的需要设置和使用 * @param what Value to assign to the returned Message.what field. * @param arg1 Value to assign to the returned Message.arg1 field. * @param arg2 Value to assign to the returned Message.arg2 field. * @param obj Value to assign to the returned Message.obj field. * @return A Message from the global message pool. */ public final Message obtainMessage(int what, int arg1, int arg2, Object obj){ return Message.obtain(this, what, arg1, arg2, obj); }/** * 使runnable对象添加到消息队列. * 这个runnable将会运行在handler所在的线程 * 如果runnable成功的添加到消息队列则返回true,否则失败。 * 如果返回false,通常是looper执行的消息循环退出了导致的 */ public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0); }/** * 添加runnable到消息队列中,让其在给定的延时后运行 * * 如果runnable成功的添加到消息队列则返回true,否则失败。 * 如果返回false,通常是looper执行的消息循环退出了导致的 * */ public final boolean postAtTime(Runnable r, long uptimeMillis){ return sendMessageAtTime(getPostMessage(r), uptimeMillis); }/** * 发布一个message到一个实现了runnable的对象中. * 通过消息队列的下一次迭代时执行该runnable. * 这个runnable将会在handler所在的线程中执行. * 这种方法只是在非常特殊的情况下使用。 * 它可以很容易地饿死消息队列,导致排序问题,或有其他意想不到的副作用。 */ public final boolean postAtFrontOfQueue(Runnable r){ return sendMessageAtFrontOfQueue(getPostMessage(r)); }/** * 同步运行指定的任务 * 如果当前线程与handler所在的线程相同, 则立即执行;否则进入消息队列排队. * </p><p> * 这种方法是危险的!使用不当可能导致死锁. * 当某些锁被占用或使用重新进入时不要调用此方法 * * 这种方法有时是有用的,在后台线程必须同步等待完成一个任务, * 必须在处理程序的线程上运行的情况下。然而,这个问题往往是糟糕的设计的一个症状。 * 考虑改进设计(如果可能),然后再使用该方法. * * 隐藏的方法 */ public final boolean runWithScissors(final Runnable r, long timeout) { if (r == null) { throw new IllegalArgumentException("runnable must not be null"); } if (timeout < 0) { throw new IllegalArgumentException("timeout must be non-negative"); }//如果handler与looper同一个线程中,则立即实行runnable的run方法。 if (Looper.myLooper() == mLooper) { r.run(); return true; }//否则构造一个BlockingRunnable任务,在给定的时间后执行 BlockingRunnable br = new BlockingRunnable(r); return br.postAndWait(this, timeout); }/** * 移除消息队列中即将执行的runnable */ public final void removeCallbacks(Runnable r){ mQueue.removeMessages(this, r, null); }/** * 移除消息队列中含有object类型的token的runnable任务 * 如果token为null,则移除所有的callbacks。 */ public final void removeCallbacks(Runnable r, Object token){ mQueue.removeMessages(this, r, token); }/** * 在当前时间之前,将一个消息推到消息队列的末尾 * message将会被发送者的handleMessage()方法收到。 */ public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg, 0); }/** * 发送一个只包含what属性值的message. */ public final boolean sendEmptyMessage(int what){ return sendEmptyMessageDelayed(what, 0); }/** * 发送一个只包含what属性值的message, 在给定的时间之后交付. */ public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); }/** * 移除消息队列中waht属性值与给定值相等的message */ public final void removeMessages(int what) { mQueue.removeMessages(this, what, null); }/** * 移除消息队列中waht属性值与给定值相等且obj属性值与给定值相等的message。 * 如果object值为null,则移除全部message */ public final void removeMessages(int what, Object object) { mQueue.removeMessages(this, what, object); }/** * 删除任何即将发布的callbacks和obj属性值为token的messages。 * 如果token是null,所有的callbacks和message将被删除。 */ public final void removeCallbacksAndMessages(Object token) { mQueue.removeCallbacksAndMessages(this, token); }/** * 检查消息队列中是否有what属性值为给定值的message. */ public final boolean hasMessages(int what) { return mQueue.hasMessages(this, what, null); }/** * 检查消息队列中是否有what、obj属性值为给定值的message. */ public final boolean hasMessages(int what, Object object) { return mQueue.hasMessages(this, what, object); }/** * 检查消息队列中是否存在含有callback的message * * @hide 隐藏的方法 */ public final boolean hasCallbacks(Runnable r) { return mQueue.hasMessages(this, r, null); }// 获取当前线程的looper public final Looper getLooper() { return mLooper; }/** * 注意此方法,参数runnable放到哪儿了? * */private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }/** * token就是message对象的obj属性值 * message也有callback属性? */private static Message getPostMessage(Runnable r, Object token) { Message m = Message.obtain(); m.obj = token; m.callback = r; return m; }/** * 调用message的callback对象的run方法。不是启动线程!!!! */private static void handleCallback(Message message) { message.callback.run(); }//前面提到的BlockingRunnable内部类private static final class BlockingRunnable implements Runnable { private final Runnable mTask; private boolean mDone; public BlockingRunnable(Runnable task) { mTask = task; } @Override public void run() { try { mTask.run(); } finally { synchronized (this) { mDone = true; notifyAll(); } } } //... }}
1、handler可以在构造的时候传递callback,以替换handleMessage方法处理消息。
2、在构造handler的时候,可以不传递looper,默认会取当前线程的looper。如果娶不到就挂了。也可以传递looper给他。
3、handler分发message时,先判断msg的callback是否有值,有则调用runnable的run方法,不是启动线程!否则判断handler的callback是否有值,有则让其处理消息。如果处理完成后return true,则handler的handleMessage(msg)不执行了,否则继续执行。
4、获取message,或许可以new,暂时还没分析。源码已经指出可以用obtain的方式从message pool中获取,效率高。
5、handler可以发及时或延时消息,可以移除部分或者全部的待处理消息。
由于篇幅太长,此文就只聊这么多,下文总结handler用法和讲解message、messageQueue。
2 0
- Android多线程消息处理机制(三) Handler部分源码分析
- android消息处理机制学习(三)-Handler,Message,MessageQueue,Looper源码分析
- Android应用程序消息处理机制(Looper、Handler)源码分析
- Android异步消息处理机制详解及源码分析 Handler
- Handler消息处理机制源码分析
- Handler消息处理机制---从源码分析
- Android Handler消息机制源码分析——第二部分: Message与Handler
- Android消息机制 Handler源码分析
- [Android] 从源码分析 Handler 消息机制
- Android Handler 消息响应机制源码分析
- Android Handler消息机制源码分析
- Android Handler消息机制源码分析
- Android源码分析之Handler消息机制
- Android 从源码分析Handler消息机制
- Android Handler消息机制源码分析
- Android应用程序消息处理机制Handler分析
- Android Handler消息机制源码分析——第一部分:Looper与MessageQueue
- 【Android消息处理机制】android的消息处理机制(图+源码分析)——Looper,Handler,Message
- pwd 显示目前的所在目录
- CSDN发代码终于整洁了
- 数字大写
- ViewPager使用fragmentadpater的注意事项
- 勾股数组的研究
- Android多线程消息处理机制(三) Handler部分源码分析
- LoadRunner11设置场景百分比模式完成多台客户端负载测试
- opencv2411和vs10的圆检测
- Axure8.0基础操作
- [Oracle] decode 函数及其用法
- 社工防不胜防的黑暗
- 安卓自定义控件之带有自定义下划线的编辑框(已经添加过图片)
- NOI2007货币兑换CASH 斜率DP CDQ分治
- offsetParent