Handler源码解析

Handler源码解析


先看几句简单的英文介绍

A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue.

一个Handler允许你发送和处理它的相关联的线程的消息队列MessageQueue上的Message消息或是Runable对象。


Each Handler instance is associated with a single thread and that thread's message queue.

每一个Handler实例都是与一个单独线程以及这个单独线程上的消息队列相关联的。


When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

当你创建一个新的Handler,他会绑定到这个线程/这个正在创建它的线程的消息队列,基于这一点,Handler将能传递Message消息和runable对象到这个消息队列上,并且当他们从消息队列中取出时来执行他们(Message消息和runable对象)。


There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.

Handler有两种主要用法:

1:定时处理message消息和runable对象在未来的每个时间

2:把一个将要在别的线程而非当前线程上执行的动作进入队列(绑定好的MessageQueue)


下面还有一段文就不翻译。。毕竟翻译水平有点low。。。

Scheduling messages is accomplished with the post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long) methods. The post versions allow you to enqueue Runnable objects to be called by the message queue when they are received; the sendMessage versions allow you to enqueue a Message object containing a bundle of data that will be processed by the Handler's handleMessage(Message) method (requiring that you implement a subclass of Handler).

When posting or sending to a Handler, you can either allow the item to be processed as soon as the message queue is ready to do so, or specify a delay before it gets processed or absolute time for it to be processed. The latter two allow you to implement timeouts, ticks, and other timing-based behavior.

When a process is created for your application, its main thread is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. You can create your own threads, and communicate back with the main application thread through a Handler. This is done by calling the same post or sendMessage methods as before, but from your new thread. The given Runnable or Message will than be scheduled in the Handler's message queue and processed when appropriate.


下面介绍让我从中文的角度来分析一下Handler的源码:


我简单的把Handler的源码分成几个部分:

1:重要的成员变量

2:四个构造方法

3:分发与处理消息:dispatchMessage(Message msg)方法与handleMessage(Message msg)

4:定时/立即发送消息Message有关的方法:以sendMessage(Message msg)方法为代表

5:发送runable对象到队列的方法:以post(Runnable r)为代表

6:获取消息Message有关的方法:以obtainMessage()方法为代表

7:移除队列中的消息/runable对象的方法:以removeCallbacks(Runnable r)和 removeMessages(int what) 为代表


一:重要的三个成员变量:

<span style="font-size:14px;">    final MessageQueue mQueue;
    final Looper mLooper;
    final Callback mCallback;
</span>
mQueue就是我们上文经常提到的那个与这个Handler实例绑定的MessageQueue的实例,基本上消息的处理都会用到这个实例的方法,即MessageQueue中的方法。

mLooper就是mQueue这个消息队列所对应的线程上的Looper对象(Looper对象在对应线程中唯一)。Looper对象简单点说就是在一个线程中不断循环的从该线程的MessageQueue消息队列中取出消息(给Handler来处理)的循环操作者。(Ps.并非每个线程都有自己的Looper对象和MessageQueue。需要程序员手动创建,具体方式可以参见Looper相关介绍)

mCallback是一个Callback类型就是一个回调函数接口嘛,Callbak是Handler中的一个内部类:(稍后分析)

<span style="font-size:14px;">    public interface Callback {
        public boolean handleMessage(Message msg);
    }</span>

这个接口定义了回调函数的名称handlerMesaage,方便编程的时候不用重写handleMessage方法,直接传入自己的回调函数即可。


二:四个构造方法

(1)最简单的默认构造方法:Handler()

<span style="font-size:14px;">public Handler() {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        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 = null;
    }
</span>
我们先不管if(FIND_POTENTIAL_LEAKS) 这个if语句。因为单纯只是输出个log,不影响操作。

mLooper = Looper.myLooper();

这句话就是对mLooper成员变量的赋值。Looper.myLooper()是Looper对象的静态方法,他会返回当前线程所拥有的那个唯一对应的Looper对象实例。(So,如果你在一个没有Looper实例的线程中用默认方式new Handler(),嘿嘿,那会报错的)

mQueue = mLooper.mQueue;

这句话就很好理解了,Looper对象也拥有线程对应的MessageQueue消息队列的引用,把这个消息队列的实例赋值给Handler,让Handler知道传递消息或runable对象去哪个线程的消息队列。

我们在来看看这个FIND_POTENTIAL_LEAKS 

<span style="font-size:14px;">    /*
     * Set this flag to true to detect anonymous, local or member classes
     * that extend this Handler class and that are not static. These kind
     * of classes can potentially create leaks.
     */
    private static final boolean FIND_POTENTIAL_LEAKS = false;</span>

这个就是告诉我们,对于一些继承了 Handler的类,可能会造成潜在的泄漏。如果找到了潜在的泄漏可能了,那么好的,执行if里面的语句,运用java反射,获取这个继承了 Handler的类名,然后打一段Log出来给你提醒一下。


(2)Handler(Callback callback) 构造方法:

与上面的代码相比仅仅有一句的不同,很容易猜出来:

<span style="font-size:14px;">//mCallback = null;
//把这句代码换成了
mCallback = callback;
</span>


(3)Handler(Looper looper)

<span style="font-size:14px;">    public Handler(Looper looper) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = null;
    }</span>

这代码很短,与Handler()默认构造函数也只有一句话的差别,但是实际上差别却很大。

比如:你在A线程中调用了new Handler()这个默认的构造方法,那么根据之前的介绍,我们绑定的线程以及线程的MessageQueue都是就是默认的A线程。

那么如何才能在A线程中创建一个属于B线程的Handler实例呢。。。这就需要用到Handler(Looper looper)这个构造方法了。

因为刚才提到过Looper与线程11对应,所以一个looper对象就可以代表那个线程。

比如我们在一个普通A线程中调用下面这句话,那么A线程就可以得到一个绑定主线程(UI线程)的Handler实例了,然后通过这个Handler对象就可以给UI线程发送更新UI的消息了。

<span style="font-size:14px;">new Handler(Looper.getMainLooper())</span>
(Looper.getMainLooper()这个静态方法会返回Looper中的叫做sMainLooper静态成员变量,对应进程中的主线程的Looper对象)

(4)public Handler(Looper looper, Callback callback) 这个函数也和之前一样,仅仅是把mCallback = null;改成mCallback = callback;


三:分发与处理消息:dispatchMessage(Message msg)方法与handleMessage(Message msg)

之前也提到过,我们用handler把消息发送到了对应的MessageQueue队列上,然后从这个消息队列中循环的取出消息让Handler来处理。

那么整个处理过程的第一部就是dispatchMessage(Message msg)方法。(在Looper对象的loop()函数中循环取出消息然后调用了msg.target.dispatchMessage(msg)进行消息的dispatch(分发))

dispatchMessage(Message msg)方法:

<span style="font-size:14px;">public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }</span>

我们可以发现所谓的分发消息,就是以不同的优先级来处理消息。

简言之,这个消息有没有自带回调函数(一般自带回调函数的消息是runable对象,有一个run()方法),有那么其他方法就没戏了。

当这个消息自己没有回调函数的时候,好吧,那么让下一层的方法来处理把,就交给了这个Handler的mCallback这个回调函数(即我们自己传入的,动态修改的回调方法)来执行这个消息的处理。

好吧,以上两种都没有的时候,属于handler类自己的handleMessage()方法才有用武之地。来处理这个没人管的消息。

(Ps.这个handleCallback(msg)是直接run()调用的方式,而非像Thread中的.start()的方式,所以,仍然是在同一个线程中运行,不会在新线程中运行)

<span style="font-size:14px;">    private static void handleCallback(Message message) {
        message.callback.run();
    }</span>




Handler源码中的handleMessage(Message msg)方法是一个空的方法,所以要求你重写这个方法或者传入一个你自己的实现了handleMessage回调函数的接口对象,用来处理消息队列中出来的消息。一个简单的实例代码:

<span style="font-size:14px;">Handler handler=new Handler(){
    		public void handleMessage(Message msg) {
    			int what = msg.what;
    			switch (what) {
				case 1:
					
					break;

				default:
					break;
				}
    			
    		};
    	};</span>
根据消息的类型进行不同的处理。更多的实例可以参考Handler具体用法。


四:定时/立即发送消息Message有关的方法:以sendMessage(Message msg)方法为代表

<span style="font-size:14px;">    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
    public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
</span>
各种sendMessage的方法都是大同小异,最后都是调用sendMessageAtTime(Message msg, long uptimeMillis)方法:uptimeMillis参数代表多少毫秒后执行。

<span style="font-size:14px;">    public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    {
        boolean sent = false;
        MessageQueue queue = mQueue;
        if (queue != null) {
            msg.target = this;
            sent = queue.enqueueMessage(msg, uptimeMillis);
        }
        else {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
        }
        return sent;
    }</span>
先判断一下,Handler关联的消息队列是否存在,如果存在那么就调用消息队列的引用,handler对象中的成员变量mQueue来进行入队列操作:queue.enqueueMessage(msg, uptimeMillis)。(具体实现参见MessageQueue源码介绍。)


五:发送runable对象到队列的方法:以post(Runnable r)为代表

直接上代码:

<span style="font-size:14px;">    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    public final boolean postAtTime(Runnable r, long uptimeMillis)
    {
        return sendMessageAtTime(getPostMessage(r), uptimeMillis);
    }
</span>
我们可以发现和sendMessage唯一的区别就是发送的对象的不同,发送的是一个runable对象,runable对象可以理解成一个自带回调函数(run())的消息,他不需要其他的handleMessage方法的处理。

一般runable对象常用于一些循环操作(I guess)。


六:获取消息Message有关的方法:以obtainMessage()方法为代表  

 

<span style="font-size:14px;">    public final Message obtainMessage()
    {
        return Message.obtain(this);
    }

    public final Message obtainMessage(int what)
    {
        return Message.obtain(this, what);
    }
    public final Message obtainMessage(int what, Object obj)
    {
        return Message.obtain(this, what, obj);
    }
</span>
本质上和Message.obtain()的一系列方法时一样的。.obtain()方法是一个对象池的技术,避免总是new message消耗内存。

  

:移除队列中的消息/runable对象的方法:以removeCallbacks(Runnable r)和 removeMessages(int what) 为代表

<span style="font-size:14px;">    public final void removeMessages(int what) {
        mQueue.removeMessages(this, what, null);
    }
    public final void removeCallbacks(Runnable r)
    {
        mQueue.removeMessages(this, r, null);
    }
</span>
本质上都是调用MessageQueue的方法removeMessages把队列上的消息去除,常用于停止runable对象的循环操作。


总结:Handler的源码还是很简单的。。。。主要就是发送消息,处理消息两个方法的使用。


他人参考文章:http://blog.csdn.net/lilu_leo/article/details/8143205

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值