android 消息循环的源码分析

简要分析android中消息循环涉及到的几个方法的源代码(API19):

1 Handler构造方法

public Handler(Callback callback, boolean async)

{       

         //检测Handler是否写成匿名内部类的形式,是则提示这有可能导致内存泄露

         //如果Handler写成匿名内部类,当我们要销毁它的外部类对象(通常为Activity)时

         //该外部类所处的线程中的messageQueue中的message持有handler,也就是匿名内部类对象本身的引用

         //而匿名内部类持有外部类的引用

         //如果messageQueue中有延迟时间很长的message,就会导致handler无法被销毁,进而导致外部类(Activity等)无法被销毁

         //造成这个问题的本质原因是handler、looper、messageQueue是threadLocal设置的线程级变量

         //其生命周期可能长于该线程中运行的Activity等外部类,而handler又被写成了内部类

         //导致内部类的生命周期长于外部类,阻止了外部类的销毁

        if (FIND_POTENTIAL_LEAKS){

            final Class<? extendsHandler> klass = getClass();

            if((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass())&&

                    (klass.getModifiers() &Modifier.STATIC) == 0) {

                Log.w(TAG, "Thefollowing Handler class should be static or leaks might occur: " +

                    klass.getCanonicalName());

            }

        }

    

     //取得当前线程的looper

    mLooper = Looper.myLooper();

 

     //当前线程没有looper则报错

        if (mLooper == null) {

            throw newRuntimeException(

                "Can't create handlerinside thread that has not called Looper.prepare()");

        }

          //从当前线程的looper中取得MessageQueue的引用

        mQueue = mLooper.mQueue;

        mCallback = callback;

        mAsynchronous = async;

         //handler建立的时候就建立和取得了本线程的looper和messagequeue

}

2 Looper的myLooper()方法

 

public static Looper myLooper() {

         //从当前looper的threadLocal线程本地变量中取出本线程拥有的looper

        return sThreadLocal.get();

}

3 Looper的构造方法

//looper对象持有一个threadLocal对象,messageQueue

staticfinal ThreadLocal<Looper> sThreadLocal = newThreadLocal<Looper>();

private staticLooper sMainLooper;

finalMessageQueue mQueue;

finalThread mThread;

//Looper的构造方法是私有的,并且在构造的时候生成了MessageQueue

private Looper(boolean quitAllowed) {

        mQueue = new MessageQueue(quitAllowed);

        mThread = Thread.currentThread();

}    

4 Looper的prepare()方法

//用该方法调用looper的构造方法创建looper

private static void prepare(boolean quitAllowed) {

        if (sThreadLocal.get()!= null) {

            throw newRuntimeException("Only one Looper may be created per thread");

        }

         //创建新的looper对象存入当前looperthreadLocal线程本地变量

        sThreadLocal.set(new Looper(quitAllowed));

         //使用threadLocal对象存储looper保证了一个线程只有一个looper

         //又因为message Queue是在looper的构造方法中建立的一个looper只有一个messageQueue

         //这样线程、loopermessageQueue实现了一一对应

         //但是handler与上述三个部件不是一一对应的一个线程的loopermessageQueue可以对应多个handler

}

5 Looper的loop()方法

//用该方法取得当前线程的looper并启动其消息循环

public static void loop() {

         //取得当前线程的looper

        final Looper me = myLooper();

        if (me == null) {

            throw newRuntimeException("No Looper; Looper.prepare() wasn't called on thisthread.");

        }                  

         //取得当前线程的MessageQueue

        final MessageQueue queue = me.mQueue;

 

        // Make sure the identity of thisthread is that of the local process,

        // and keep track of what that identitytoken actually is.

        Binder.clearCallingIdentity();

        final long ident =Binder.clearCallingIdentity();

        

         //开启一个死循环,从messageQueue中取出下一条消息,取出的动作可能是阻塞的

        for (;;){

            Message msg = queue.next(); // might block

            if (msg == null) {

                // No message indicates thatthe message queue is quitting.

                return;

            }

 

            // This must be in a localvariable, in case a UI event sets the logger

            Printer logging = me.mLogging;

            if (logging != null){

               logging.println(">>>>> Dispatching to " +msg.target + " " +

                        msg.callback + ": " +msg.what);

            }

                   

             //将从messageQueue中取得的消息发送给该消息指定的handler去处理

            msg.target.dispatchMessage(msg);

 

            if (logging != null){

               logging.println("<<<<< Finished to " +msg.target + " " + msg.callback);

            }

 

            // Make sure that during the courseof dispatching the

            // identity of the thread wasn'tcorrupted.

            final long newIdent =Binder.clearCallingIdentity();

            if (ident != newIdent) {

                Log.wtf(TAG,"Thread identity changed from 0x"

                        + Long.toHexString(ident)+ " to 0x"

                        + Long.toHexString(newIdent)+ " while dispatching to "

                        +msg.target.getClass().getName() + " "

                        + msg.callback + "what=" + msg.what);

            }

             

           //handler处理完消息后将其回收

            msg.recycle();

        }

    }

 6 MessageQueue的的next()方法

//messageQueue中取出下一个消息

Message next() {

              ......................

                      

              //在取消息时用同步锁锁住messageQueue,防止不同线程的 handler同时操作messageQueue

            synchronized (this) {

                // Try to retrieve the nextmessage.  Return if found.

                final long now =SystemClock.uptimeMillis();

                Message prevMsg = null;

                Message msg = mMessages;

                 

                //从前向后遍历链表,找到第一个异步(其它线程发来的)消息

               if (msg != null && msg.target == null) {

                    // Stalled by abarrier.  Find the next asynchronousmessage in the queue.

                    do {

                        prevMsg = msg;

                        msg = msg.next;

                    } while (msg != null &&!msg.isAsynchronous());

                }

                //由于messageQueueenqueueMessage()方法在将message插入消息链表的时候根据消息的执行时间进行了排序

                //所以之前找到的第一个异步消息一定是执行时间最早的异步消息

                if (msg!= null) {

                      //如果当前时间早于执行时间最早的异步消息的执行时间,不执行

                   if (now < msg.when) {

                        // Next message is notready.  Set a timeout to wake up when itis ready.

                        nextPollTimeoutMillis =(int) Math.min(msg.when - now, Integer.MAX_VALUE);

                     //如果当前时间晚于执行时间最早的异步消息的执行时间,返回这个异步消息给looper

                   } else {

                        // Got a message.

                        mBlocked = false;

                        if (prevMsg != null){

                            prevMsg.next =msg.next;

                        } else {

                            mMessages =msg.next;

                        }

                        msg.next = null;

                        if (false)Log.v("MessageQueue", "Returning message: " + msg);

                        msg.markInUse();

                        return msg;

                    }

                } else {

                    // No more messages.

                    nextPollTimeoutMillis = -1;

                }

                  ................................

    }

7 MessageQueue的enqueueMessage()方法

boolean enqueueMessage(Message msg, long when) {

        if (msg.isInUse()) {

            throw newAndroidRuntimeException(msg + " This message is already in use.");

        }

        if (msg.target == null) {

            throw newAndroidRuntimeException("Message must have a target.");

        }

 

        synchronized (this) {

            if (mQuitting) {

                RuntimeException e = newRuntimeException(

                        msg.target + " sending messageto a Handler on a dead thread");

                Log.w("MessageQueue",e.getMessage(), e);

                return false;

            }

 

            msg.when = when;

            Message p = mMessages;

            boolean needWake;

              //按照message自带的执行时间将message插入到消息链表中,执行时间早的插入到靠前的位置

            if (p ==null || when == 0 || when < p.when) {

                // New head, wake up the eventqueue if blocked.

                msg.next = p;

                mMessages = msg;

                needWake = mBlocked;

            } else {

                // Inserted within the middleof the queue.  Usually we don't have towake

                // up the event queue unlessthere is a barrier at the head of the queue

                // and the message is theearliest asynchronous message in the queue.

                needWake = mBlocked &&p.target == null&& msg.isAsynchronous();

                Message prev;

                for (;;) {

                    //向后遍历消息链表

                    prev = p;

                    p = p.next;

                    if (p == null|| when < p.when) {

                        break;

                    }

                    if (needWake&& p.isAsynchronous()) {

                        needWake = false;

                    }

                }

                //将入队的消息插入到消息链表中合适的位置

                msg.next = p; // invariant: p == prev.next

                prev.next = msg;

            }

 

            // We can assume mPtr != 0 becausemQuitting is false.

            if (needWake) {

                nativeWake(mPtr);

            }

        }

        return true;

    }

8  Handler的dispatchMessage()方法

//looper调用handler的此方法messageQueue中取出的message传给此方法

//此方法按优先级依次查找三种方法来处理message,找到就结束找不到再去找下一个优先级的方法

//优先级1:message自己指定的处理方法

//优先级2:handler在构造时传入的Handler.Callback接口的实现对象所重写的handleMessage()方法

//优先级3:handler被覆盖的handleMessage()方法

public void dispatchMessage(Message msg) {

        if (msg.callback != null){

            handleCallback(msg);

        } else {

            if (mCallback != null){

                if (mCallback.handleMessage(msg)) {

                    return;

                }

            }

            handleMessage(msg);

        }

}    

------------------------------------------------------我是分割线-----------------------------------------------------------------------------

看过了上面几个跟消息循环有关的方法,我们可以总结一下一个消息从生到死的全过程啦:

消息循环流程:

0. Looper类中有一个静态成员变量threadLocal对象

1. Looper.prepare():

     (Looper类的静态方法)

     构造looper对象,looper对象在构造时构造messageQueue对象,

     用Looper类的静态threadLocal对象将构造出来的looper对象设定为线程级变量

2. Handler handler = new Handler(){   @Override public void handleMessage(Messagemsg){.........}}  

     构造Handler继承类的对象,重写其handleMessage()方法

     构造时调用Looper类的静态方法myLooper()从Looper类的静态threadLocal对象中取得当前线程所拥有的looper对象

     此时handler拥有了当前线程的looper和messageQueue对象

3. Looper.loop()

     (Looper类的静态方法)

     调用Looper类的静态方法myLooper()从Looper类的静态threadLocal对象中取得当前线程所拥有的looper对象,

     开启死循环不停地调用messageQueue的next()方法以阻塞方式从刚才取得的looper对象中包含的messageQueue中获取下一个message

     将获取的message传给message的target所指定的handler的dispatchMessage()方法

     后者依据优先级调用Handler.Callback或者handler类方法的handleMessage()来处理消息

4. handler.sendMessage(Message msg):

     将传入message的target设定成自己

     调用当前线程的messageQueue的enqueueMessage()方法将传入的message按照message执行时间先后顺序插入messageQueue

5. 第3步和第4步同时进行

     handler.sendMessage(Messagemsg)通过调用messageQueue的enqueueMessage()将消息加入消息队列

     Looper.loop()通过messageQueue的next()方法将消息从消息队列中取出,发给其指定的handler的handleMessage()方法处理

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值