• 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解决这种线程同步问题的方案,简单而使用。

  • 相关阅读:
    POJ2425 A Chess Game[博弈论 SG函数]
    POJ1740A New Stone Game[组合游戏]
    Vijos P1196吃糖果游戏[组合游戏]
    CF724D. Dense Subsequence[贪心 字典序!]
    CF724B. Batch Sort[枚举]
    CF731C. Socks[DFS 贪心]
    CF733D Kostya the Sculptor[贪心 排序]
    CF733C Epidemic in Monstropolis[模拟 构造 贪心]
    洛谷P1991无线通讯网[kruskal | 二分答案 并查集]
    NOIP2015斗地主[DFS 贪心]
  • 原文地址:https://www.cnblogs.com/chiefhsing/p/2847953.html
Copyright © 2020-2023  润新知