Android多线程消息处理机制(三) Handler部分源码分析

来源:互联网 发布:最好小额网络投资理财 编辑:程序博客网 时间:2024/05/19 23:15
此文一起来看下Handler的部分源码,不用怕很简单,有英文的地方我都翻译了。
把里面相关的方法过一眼,你瞬间会明白很多。高手就不用看了,去过你的荣华富贵花天酒地。
我一致认为,想学好某一技术,首先是了解原理和熟练使用,其次是钻研其源码,看他是怎么做的。
万万不可随便在网上搜篇文章做一个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
原创粉丝点击