Handler,Looper,MessageQueue(Message)

1.Looper

先介绍Looper吧,顾名思义就是环、回路,意味着循环。Looper是对消息循环的封装,可理解为一个消息队列,可以添加和循环获取其中内容。它与一个具体线程相关,从SDK中Looper的注释有一个最简单的例子,表明它和线程的关系:

 1    class LooperThread extends Thread {
 2        public Handler mHandler;
 3        
 4        public void run() {
 5            Looper.prepare();
 6            
 7            mHandler = new Handler() {
 8                public void handleMessage(Message msg) {
 9                    // process incoming messages here
10                }
11            };
12            
13            Looper.loop();
14        }
15    }

当使用

new LooperThread().start()

  

时执行run()方法,先调用Looper.prepare(),该方法做什么东西:

1     public static final void prepare() {
2         if (sThreadLocal.get() != null) {
3             throw new RuntimeException("Only one Looper may be created per thread");
4         }
5         sThreadLocal.set(new Looper());
6     }

sThreadLocal是一个Looper的静态全局变量,一开始就初始化了

1 private static final ThreadLocal sThreadLocal = new ThreadLocal();

然后调用sThreadLocal.set(new Looper()):

1     public void set(T value) {
2         Thread currentThread = Thread.currentThread();//获取当前线程
3         Values values = values(currentThread);
4         if (values == null) {
5             values = initializeValues(currentThread);
6         }
7         values.put(this, value);//简单理解为把传进来的Looper对象value保存起来
8     }

set()方法的作用主要是把传进来的Looper和当前的线程建立一个关联关系

然后Looper.prepare()的过程完成,接下来调用Looper.loop(),接下来就是new一个Handler对象,这里先不介绍,后面会说,最后loop()方法执行内容:

    /**
     *  Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static final void loop() {
        Looper me = myLooper();//myLooper()作用就是把刚好set(T value)中保存的Looper取出来
        MessageQueue queue = me.mQueue;//每一个Looper都有自己的MessageQueue
        while (true) {//无限循环执行
            Message msg = queue.next(); // might block取出一条Message
            //if (!me.mRun) {
            //    break;
            //}
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }
                if (me.mLogging!= null) me.mLogging.println(
                        ">>>>> Dispatching to " + msg.target + " "
                        + msg.callback + ": " + msg.what
                        );
                msg.target.dispatchMessage(msg);//msg.target是一个Handler对象,然后分发msg
                if (me.mLogging!= null) me.mLogging.println(
                        "<<<<< Finished to    " + msg.target + " "
                        + msg.callback);
                msg.recycle();
            }
        }
    }

由于该无限循环牵涉到MessageQueue(Message),所以接下来简单介绍一下MessageQueue和Message。 

2.MessageQueue和Message

其实MessageQueue很简单,从名字就知道它是一个消息队列,只是一个“数据存储结构”而已,保存的Message对象。而该存储结构可以理解为一个链表,每一个Message对象中包含一个next变量用于引用下一个Message对象,理解为一个指针。每一个Looper对象都有自己的MessageQueue,MessageQueue是Looper的一个全局变量,在构造函数的时候就赋值了:

1     private Looper() {
2         mQueue = new MessageQueue();
3         mRun = true;
4         mThread = Thread.currentThread();
5     }

 

MessageQueue的方法基本就是获取消息队列中的Message对象,这里不做详细解释。

介绍一下Message,它有几个重要的全局变量:

 1     /**
 2      * User-defined message code so that the recipient can identify 
 3      * what this message is about. Each {@link Handler} has its own name-space
 4      * for message codes, so you do not need to worry about yours conflicting
 5      * with other handlers.
 6      */
 7     public int what;//用户定义的标识,可以理解为id
 8 
 9     // Use these fields instead of using the class's Bundle if you can. 
10     /** arg1 and arg2 are lower-cost alternatives to using {@link #setData(Bundle) setData()}
11     if you only need to store a few integer values. */
12     public int arg1; //如果希望带上简单的int数据可以用这个参数,而不需要用Bundle
13 
14     /** arg1 and arg2 are lower-cost alternatives to using {@link #setData(Bundle) setData()}
15     if you only need to store a few integer values.*/ 
16     public int arg2;
17 
18     /** An arbitrary object to send to the recipient.  This must be null when
19      * sending messages across processes. */
20     public Object obj;//发送给接收者的任意对象,当夸进程发送时必须为空
21 
22     /** Optional Messenger where replies to this message can be sent.
23      */
24     public Messenger replyTo;
25     
26     /*package*/ long when;//主要用户保存时间
27     
28     /*package*/ Bundle data;//数据
29     
30     /*package*/ Handler target;    //将要处理该消息的Handler对象 
31     
32     /*package*/ Runnable callback; //回调函数  
33     
34     // sometimes we store linked lists of these things
35     /*package*/ Message next;//指向MessageQueue中的下一个Message,这样MessageQueue就构成了一个链式结构

 

从上面看,貌似 Handler,Looper,MessageQueue(Message)三者还没有什么联系,特别是Handler,那接下来就介绍Handler

3.Handler

刚才省略了说明的一步:

1   *          mHandler = new Handler() {
2   *              public void handleMessage(Message msg) {
3   *                  // process incoming messages here
4   *              }
5   *          };

这里就是一个构造函数,那么这个构造函数究竟做了什么:

 1     /**
 2      * Default constructor associates this handler with the queue for the
 3      * current thread.
 4      *
 5      * If there isn't one, this handler won't be able to receive messages.
 6      */
 7     public Handler() {
 8         if (FIND_POTENTIAL_LEAKS) {
 9             final Class<? extends Handler> klass = getClass();
10             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
11                     (klass.getModifiers() & Modifier.STATIC) == 0) {
12                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
13                     klass.getCanonicalName());
14             }
15         }
16 
17         mLooper = Looper.myLooper();//这里解释确定刚才Looper.prepare()时set的Looper对象(哈哈,有联系了吧)
18         if (mLooper == null) {
19             throw new RuntimeException(
20                 "Can't create handler inside thread that has not called Looper.prepare()");
21         }
22         mQueue = mLooper.mQueue;//把自己的全局的MessageQueue变量mQueue指向了本线程中Looper对象的MessageQueue
23         mCallback = null;
24     }

然后我们执行一个简单的发送消息函数,例如:

 1     /**
 2      * Sends a Message containing only the what value.
 3      *  
 4      * @return Returns true if the message was successfully placed in to the 
 5      *         message queue.  Returns false on failure, usually because the
 6      *         looper processing the message queue is exiting.
 7      */
 8     public final boolean sendEmptyMessage(int what)
 9     {
10         return sendEmptyMessageDelayed(what, 0);
11     }

一直往下看,会执行:

    /**
     * Enqueue a message into the message queue after all pending messages
     * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
     * You will receive it in {@link #handleMessage}, in the thread attached
     * to this handler.
     * 
     * @param uptimeMillis The absolute time at which the message should be
     *         delivered, using the
     *         {@link android.os.SystemClock#uptimeMillis} time-base.
     *         
     * @return Returns true if the message was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.  Note that a
     *         result of true does not mean the message will be processed -- if
     *         the looper is quit before the delivery time of the message
     *         occurs then the message will be dropped.
     */
    public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    {
        boolean sent = false;
        MessageQueue queue = mQueue;//又取得了Looper中的MessageQueue
        if (queue != null) {
            msg.target = this;//看到了没!!!!!!!!Message对象的target变量为this,也就是,Message对象持有了该Handler
            sent = queue.enqueueMessage(msg, uptimeMillis);
        }
        else {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
        }
        return sent;
    }

代码中可见,当发送一个消息时,先会取得Looper中的MessageQueue,使的Handler自己的MessageQueue和Looper的MessageQueue引用的是同一个对象,而消息本身又持有了当前的Handler对象,然后这个消息就会进入到Looper的MessageQueue中了(通过MessageQueue.enqueueMessage()实现)

回头看Looper.loop()的一段代码:

1 msg.target.dispatchMessage(msg);

看到没有,最终把Message分发出去的其实就是Message自己持有的那个Handler对象target

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

调用Handler自己的回调对象处理消息。

回顾上面,Handler,Looper,MessageQueue(Message)三种的关系就清晰了:线程关联一个对象Looper(Looper.prepare()实现),Looper一直循环在取它自己的MessageQueue中的消息Message(通过调用Looper.loop()可见),如果有消息的话,就会把消息分发出去,而该消息的分发就是通过Handler实现分发的,而Handler发送消息时,则是往Looper.MessageQueue中添加消息,等待Looper.loop()不断循环时把自己分发出去。三者关系就是这么简单,无论是发消息还是处理消息,都是Handler帮助实现的,所以可以把Handler看做成一个工具类。

 

Handler通常用于:当需要新开线程执行一些耗时的操作时,等到结果返回时,用它来实现UI的更新。

从上面分析可知,要想实现这个,Handler就需要持有UI线程的Looper,这个很容易实现,通过构造函数:

1     /**
2      * Use the provided queue instead of the default one.
3      */
4     public Handler(Looper looper) {
5         mLooper = looper;
6         mQueue = looper.mQueue;
7         mCallback = null;
8     }

当新开线程运行后,就可以通过这个关联了UI线程的Looper的Handler对象发送消息,然后在通过handlerMessage()在UI线程里更新了:

1 new Thread(new Runable(){
2       @Override
3       run(){
4         mHandler.sendEmptyMessage(0);
5     }   
6 }
7 ).start()

 

 

注意,很经常我们会这样做:

1 Runable r = new Runable(){
2     run(){
3     ......         
4     }
5 }
6 
7 mHandler.post(r);

理所当然的认为,貌似是新开了一个线程去执行run()里面的方法,因为Runnable的作用太深入人心了,而事实不然,请看:

 1     /**
 2      * Causes the Runnable r to be added to the message queue.
 3      * The runnable will be run on the thread to which this handler is 
 4      * attached. 
 5      *  
 6      * @param r The Runnable that will be executed.
 7      * 
 8      * @return Returns true if the Runnable was successfully placed in to the 
 9      *         message queue.  Returns false on failure, usually because the
10      *         looper processing the message queue is exiting.
11      */
12     public final boolean post(Runnable r)
13     {
14        return  sendMessageDelayed(getPostMessage(r), 0);//post做得只是这个,就是放松了一条消息那么简单,并没有任何新开一条线程的意思
15     }

而Runnable对象究竟有什么用,看getPostMessage(r):

1     private final Message getPostMessage(Runnable r) {
2         Message m = Message.obtain();//它就是获取一条新消息
3         m.callback = r;//r只是作为了Message对象的callback变量
4         return m;
5     }

最后r会发生什么作用:

 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     }

callback不为空时,会干什么:

 

1     private final void handleCallback(Message message) {
2         message.callback.run();
3     }

当Handler分发消息时会干什么?它就是执行了Runnable的run()方法,像一般函数一样,奇葩了吧,而且Handler会收不到消息,因为虽然貌似“发送”了,其实没有,只是执行了run方法而已。。。。

所以当你想Handler能够收到消息,请在run()方法中,写上mHandler.sendEmptyMessage(0)。这种形式使用Handler基本是用于按计划发送消息或者执行一个Runnable。

 


最后说一下HandlerThread,HandlerTread继承与Thread,它有什么不同?先看下面:

 

1 class MyThread extends Thread{
2     public Looper looper = null;
3 
4     public void run(){
5         Looper.prepare();
6         looper = Looper.myLoop();
7         Looper.loop();}
8 }            

 

在UI线程(或者是自己的其他 线程中)定义上面这样的一个Thread:

1 MyThread myThread = new MyThread();
2 myThread.start();
3 Looper myLooper = myThread.myLooper();
4 Handler handler = new Handler(myLooper);
5 handler.sentEmptyMessage(0);

这种情况极有可能因为线程的同步问题而出错,看代码知,当MyThread.start()后,线程执行到哪里是不可确定的,有可能Looper.prepare()没有执行,这时候,把myThread.myLooper()的值赋给myLooper就是NULL,这样就会出错。所以多线程下的同步还是很重要的,而HandlerThread()就是给我们解决了这个问题,看它重要的两个方法,一个是获得Looper对象的getLooper(),另一个就是run():

 1     public void run() {
 2         mTid = Process.myTid();
 3         Looper.prepare();
 4         synchronized (this) {
 5             mLooper = Looper.myLooper();
 6             Process.setThreadPriority(mPriority);
 7             notifyAll();//保证执行完prepare()后,唤醒
 8         }
 9         onLooperPrepared();
10         Looper.loop();
11         mTid = -1;
12     }
13     
14     /**
15      * This method returns the Looper associated with this thread. If this thread not been started
16      * or for any reason is isAlive() returns false, this method will return null. If this thread 
17      * has been started, this method will block until the looper has been initialized.  
18      * @return The looper.
19      */
20     public Looper getLooper() {
21         if (!isAlive()) {
22             return null;
23         }
24         
25         // If the thread has been started, wait until the looper has been created.
26         synchronized (this) {
27             while (isAlive() && mLooper == null) {
28                 try {
29                     wait();//如果mLooper为空,则表明还没有调用prepare方法,就等待
30                 } catch (InterruptedException e) {
31                 }
32             }
33         }
34         return mLooper;
35     }

上面注释部分明显看出,HandlerThread解决这种线程同步问题的方案,简单而使用。

 

posted on 2013-01-06 16:52  wacao  阅读(600)  评论(0编辑  收藏  举报

导航