Android Handler的使用示例:结合源码理解Android Handler机制(一)

什么是Handler?

 Android 的官方解释:

文档分节1:A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. 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可以发送和处理两种类型的事物:

1,Message;

2,实现Runnable接口的对象

二,每个Handler实例都会跟创建Handler的Thread及这个Thread下的MessageQueue相关联。

文档分节2: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和Runnable对象

2,可以在不同的线程中去执行某项任务

文档分节3: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).

Handler主要提供了两种方式来调度消息:

1,post方式:处理Runnable对象

2,sendmessage方式:在Message中放入Bundle data,这个消息会在Handler提供的handleMessage(Message)方法中去处理;

文档分节4: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-basedbehavior.

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. Thegiven Runnable or Message will then be scheduled in the Handler's message queue and processed when appropriate.

1,我们可以让handler马上或者指定一个时间间隔发送消息;

2,当我们的应用开启时,UI线程会自动帮我们创建好MessageQueue,我们也可以在自己定义的Thread中创建。

这些信息我们现在只要稍微有个概念就好,一会进入Handler的深入分析之后,自然就会清楚,我们先来分析一下Handler的源码:

先来看看Handler主要的成员变量:

 final MessageQueue mQueue;
 final Looper mLooper;
 final Callback mCallback;
 final boolean mAsynchronous;
 IMessenger mMessenger;

 我们先粗略地看一下,Handler这个类里面有MessageQueue,从名称中我们可以猜测,这个就应该是消息队列了,第二个成员变量:Looper,从名称来看,应该是个推动消息循环的角色,第三个成员变量:Callback,应该是个回调的接口,剩下的两个先暂时忽略,这三个比较重要的成员变量咱们先混个眼熟,打个招呼就好,现在我们来看一下这个类的构造方法,依次先从最简洁的构造方法看起:

    public Handler() {
        this(null, false);
    } 
 public Handler(Callback callback) {
        this(callback, false);
    }
    public Handler(Looper looper) {
        this(looper, null, false);
    }
    public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }
    public Handler(boolean async) {
        this(null, async);
    }
 1    public Handler(Callback callback, boolean async) {
 2         if (FIND_POTENTIAL_LEAKS) {
 3             final Class<? extends Handler> klass = getClass();
 4             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
 5                     (klass.getModifiers() & Modifier.STATIC) == 0) {
         //想必大家对下面这句话不陌生吧?细心的朋友们会经常在开发环境中看到这句黄色警告(该Handler可能会导致内存泄漏),后面的系列我们再给出解决这个警告的示例代码
6 Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 7 klass.getCanonicalName()); 8 }
9 } 10 11 mLooper = Looper.myLooper(); 12 if (mLooper == null) { 13 throw new RuntimeException(
//这个抛出的异常信息大家也可能一不小心就会看到
14 "Can't create handler inside thread that has not called Looper.prepare()"); 15 } 16 mQueue = mLooper.mQueue; 17 mCallback = callback; 18 mAsynchronous = async; 19 }
1     public Handler(Looper looper, Callback callback, boolean async) {
2         mLooper = looper;
3         mQueue = looper.mQueue;
4         mCallback = callback;
5         mAsynchronous = async;
6     }

我了个大去,稍微看去洋洋洒洒出现了7个构造方法,仔细看下,其实前面五种构造方法都调用到了最后两种构造方法中的一种,那么我们就着重来看一下这两个构造方法

public Handler(Callback callback, boolean async)的构造方法里面都干了些啥?
1,通过Looper的myLooper()方法,得到一个Looper对象,将之传给Handler的成员变量mLooper;
如果拿到的这个对象为null,就会抛出异常,从异常的信息来看,说是没有在创建Handler的时候去调用Looper的prepare()方法;
2,从得到的Looper对象拿出MessageQueue对象,传给Handler的成员变量mQueue;
3,将入参callback传给Handler的成员变量mCallback;
看到这里,朋友们可能会发现这个Looper看来是个重要角色啊,忍不住想去一窥究竟,先忍一忍,好戏总是在后头,先来看一下另外一个重要的构造方法
public Handler(Looper looper, Callback callback, boolean async)
其实这个方法做的就是上面那个构造方法的事情,只不过,mLooper,mQueue,mCallback都是在调用之前就已经创建好了,直接赋值而已

上面已经看了Handler这个类的成员变量,构造方法,那么,我们现在就来看一下这个类里面都给外部提供了哪些接口和方法
    public interface Callback {
        public boolean handleMessage(Message msg);
    }

原来Callback真的就是一个接口,提供了一个回调的方法 handleMessage(Message msg),这个方法的名字有点熟悉,是不是就是我们经常见到的那个在新创建一个Handler的时候,需要覆盖的方法呢?先带着疑问往下看,

 /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }

看到这个类的注解,大家马上发现上面的疑问是自己多想了,两个方法虽然同名,但是返回类型不同啊,原来这个方法才是我们常见的那个需要覆盖的方法。

接着往下看,

在文章开头的文档分节3中,我们知道,Handler主要提供了两种方式来发送消息,一种是postXX方法,一种是sendMessageXX方法

果然,我们看到了大量的post和sendmessage方法

    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

 

 

   public final boolean postAtTime(Runnable r, long uptimeMillis)
    {
        return sendMessageAtTime(getPostMessage(r), uptimeMillis);
    }

 

 

 public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
    {
        return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
    }

 

 

 public final boolean postDelayed(Runnable r, long delayMillis)
    {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }

 

 

public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

 

 

    public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }

 

 

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }

 

 

 public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
    }

 

 

public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

 

 

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);
    }

 

细心的朋友们仔细一看,就能发现,其实不管是postXX还是sendMessageXX方法,最终调用的都是sendMessageAtTime这个方法,postXX方法只是不是多调了getPostMessage()方法而已 ,那么我们就来看一下这个方法做了些什么事情:

  private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

    private static Message getPostMessage(Runnable r, Object token) {
        Message m = Message.obtain();
        m.obj = token;
        m.callback = r;
        return m;
    }

首先获取一个Message,然后把Runnable对象传递给Message的callback变量,返回一个Message;

我们在文章开头中的Handler的官方文档中提到这么一句话

A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue.
那么,这里的callback就是这个Runnable object了!
然后我们接着看sendMessageAtTime到底做了些啥?关键的代码就在最后一句:
return enqueueMessage(queue, msg, uptimeMillis);
从这个方法名中,我们可以知道它是让这个消息入列,我们来看一下它的具体实现:
 1 boolean enqueueMessage(Message msg, long when) {
 2         if (msg.target == null) {
 3             throw new IllegalArgumentException("Message must have a target.");
 4         }
 5         if (msg.isInUse()) {
 6             throw new IllegalStateException(msg + " This message is already in use.");
 7         }
 8 
 9         synchronized (this) {
10             if (mQuitting) {
11                 IllegalStateException e = new IllegalStateException(
12                         msg.target + " sending message to a Handler on a dead thread");
13                 Log.w("MessageQueue", e.getMessage(), e);
14                 msg.recycle();
15                 return false;
16             }
17 
18             msg.markInUse();
19             msg.when = when;
20             Message p = mMessages;
21             boolean needWake;
22             if (p == null || when == 0 || when < p.when) {
23                 // New head, wake up the event queue if blocked.
24                 msg.next = p;
25                 mMessages = msg;
26                 needWake = mBlocked;
27             } else {
28                 // Inserted within the middle of the queue.  Usually we don't have to wake
29                 // up the event queue unless there is a barrier at the head of the queue
30                 // and the message is the earliest asynchronous message in the queue.
31                 needWake = mBlocked && p.target == null && msg.isAsynchronous();
32                 Message prev;
33                 for (;;) {
34                     prev = p;
35                     p = p.next;
36                     if (p == null || when < p.when) {
37                         break;
38                     }
39                     if (needWake && p.isAsynchronous()) {
40                         needWake = false;
41                     }
42                 }
43                 msg.next = p; // invariant: p == prev.next
44                 prev.next = msg;
45             }
46 
47             // We can assume mPtr != 0 because mQuitting is false.
48             if (needWake) {
49                 nativeWake(mPtr);
50             }
51         }
52         return true;
53     }

分析第2行:msg.target,这个target指的是啥呢?我们这里先暂时不管,后来具体分析Message这个类的时候,我们会分析到

分析第10行:mQuitting,如果这个变量为true,那么就会抛出一个异常,在后续的分析IntentService的时候,我们会遇到这个异常,在这里先有个印象;

分析第33-45行:这里就是把消息按照消息的时间顺序进行排列而已,即把消息队列中的消息按照时间进行排序,并没有执行真正的入列操作,那什么时候执行真正的入列操作呢?后面分析Looper这个类的时候,我们会分析到

 



 1  /**
 2      * Handle system messages here.
 3      */
 4     public void dispatchMessage(Message msg) {
 5         if (msg.callback != null) {
 6             handleCallback(msg);
 7         } else {
 8             if (mCallback != null) {
 9                 if (mCallback.handleMessage(msg)) {
10                     return;
11                 }
12             }
13             handleMessage(msg);
14         }
15     }

从方法名称来看,这个方法是用来分发消息的,我们进入方法里面看一下,首先先判断Message的callback是否为空,这个callback到底是个啥?跟进去看一下

    /*package*/ Runnable callback;

是个Runnable,这里就是我们在getPostMessage这个方法中提到的把Runnable对象传递给Message的callback变量,也就是说,如果我们调用Hander的postXX的方法,那么就会把这个Runnable对象赋值给Message的callback变量,那么在上述代码的第五行中,当这个变量不为空的时候,就会调用handleCallback(msg):这个方法去处理消息,

private static void handleCallback(Message message) {
        message.callback.run();
    }

看到这里,大家就明白了,我们调用Handler 的postXX方法时,可以在这个Runnalble对象的run方法里去执行UI操作了。

接着分析上面代码的else分支,

1 else {
2             if (mCallback != null) {
3                 if (mCallback.handleMessage(msg)) {
4                     return;
5                 }
6             }
7             handleMessage(msg);
8         }

如果Handler的mCallback成员变量如果不为空,那么就调用这个接口的handleMessage方法,否则的话,就走handleMessage(msg)方法,

    /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }

好了,这下终于到我们比较熟悉的Handler的处理消息方法上去了,这个方法就是我们在Handler里处理UI操作的方法了。

 

本篇只是单独地对Handler这个类分析它的内部实现及对外提供的接口及方法,并没有对与Handler紧密相关联的Looer类,MessageQueue类,Message进行分析,目的是为了清晰地对单个封闭的类进行感性的认识之后,再对与之关联的类相互之间的关联调用进行分析;

总结:

1,Handler可以处理 Message及Runnable对象;

2,Handler提供多种构造方法,从而得到与之紧密关联的Looper对象,MessageQueue对象等;

3,Handler提供了两种类型的发送消息的方法,post版本及sendMessage版本

4,Handler提供了重要的dispatchMessage方法,在这个方法中明确是把消息给Runnable对象的run方法还是给Handler子类的handlMessage方法执行UI操作。

 


 
posted @ 2015-12-19 16:08  crash_coder  阅读(376)  评论(0编辑  收藏  举报