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

此文一起来看下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。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值