android源码随笔——消息循环机制

在学习android过程中,我们是知道的,一个线程对应一个Loop,同时Activity默认的UI线程会有对应的默认生成的Loop,那么为什么这样呢?没事看看源码可以得到更多的信息。

 

我们从使用主线程的Looper分析:

Activity被被创建之前,会首先创建UI线程,也就是ActivityThread实例,其中含有入口。

publicstaticvoid main(String[] args)中含有

   Looper.prepareMainLooper();来创建该UI线程中的Looper

Looper.loop();来循环控制分发所得到的Message

由此,Activity便默认产生了一个UI线程的Loop

 

那么这时候呢,这个主Loop便在UI线程不断的循环,一直跑。

 

下面来看看Loop的源码,其实主要要注意两个方法prepare()loop()

其中主要是:

   publicstaticvoid prepare() {

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

            thrownew RuntimeException("Only one Looper may be created per thread");}

        sThreadLocal.set(new Looper());}//Prepare()用于初始化Looper实例


 

 private Looper() {

        mQueue = new MessageQueue();//同时初始化了MessageQueue()

        mRun = true;

        mThread = Thread.currentThread();

}


首先之前的判断语句保证了,一个线程里只能含有一个Looper实例,否则要出问题。

 

下面来看看sThreadLocal变量,可以来看看这个是表示的什么:

Staticfinal ThreadLocal<Looper>sThreadLocal =new ThreadLocal<Looper>();

ThreadLocal类的源码,可以了解到,其实就是一个通用容器,含有get(),set()等等方法,这里用于存放Looper实例。

 

接下来我们看看sThreadLocal.set(new Looper());这个语句都做了些啥?

   publicvoid set(T value) {

        Thread currentThread = Thread.currentThread();

        Values values = values(currentThread);

        if (values == null) {

            values = initializeValues(currentThread);

        }

        values.put(this, value);

    }


原来set中所做的工作无非就是初始化Values(如果当前线程并没有初始化Values的时候),并将对应的Looper实例放入Values中一个Object数组中(table),这个存放的Values是以Thread作为划分的。

 

OK,接下面来分析Loop方法:

publicstaticvoid loop() {

//获取当前线程存在的Looper对象

        Looper me = myLooper(); 

        if (me == null) {

            thrownew RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");

        }

//获取该Looper对象中的MessageQueue实例

        MessageQueue queue = me.mQueue; 

 

        // Make sure the identity of this thread is that of the local process,

        // and keep track of what that identity token actually is.

        Binder.clearCallingIdentity();

        finallong ident = Binder.clearCallingIdentity();

        //一个无线循环遍历该MessageQueue对象,获取对应的含有的Message对象

        while (true) {

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

            if (msg != null) {

                if (msg.target == null) {  

//这里提前说明下msg.target其实就是对应的Handler对象

                    // No target is a magic identifier for the quit message.

                    return;

                }

                long wallStart = 0;

                long threadStart = 0;

                // This must be in a local variable, 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);

                    wallStart = SystemClock.currentTimeMicro();

                    threadStart = SystemClock.currentThreadTimeMicro();

                }

//调用Handler的消息分发方法,下面详细介绍

                msg.target.dispatchMessage(msg);

 

          if (logging != null) {

             long wallTime = SystemClock.currentTimeMicro() - wallStart;

              long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;

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

                    if (logging instanceof Profiler) {

                        ((Profiler) logging).profile(msg, wallStart, wallTime,

                                threadStart, threadTime);

                    }

                }

 

                // Make sure that during the course of dispatching the

                // identity of the thread wasn't corrupted.

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

                }

                

                msg.recycle();//消息分发以后,释放该Message实例

            }

        }

}


总而观之,loop要做的事情就是不断的在该线程中循环遍历该Looper实例所对应的MessageQueue.如果MessageQueue被塞入了Message,则将其dispatchMessage掉。

这里可以知道msg.target.dispatchMessage(msg);中的msg.target就是Message对应的Handler实例,来源可以来看Handler的源码。

我们在平时使用Handler的时候无非就是初始化,然后使用sendMessage,然后handleMessage

 

一起来分析下,首先是初始化工作:

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) {

            thrownew RuntimeException(

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

        }

        mQueue = mLooper.mQueue;

        mCallback = null;

}


看看myLooper是个啥东东。  

 publicstatic Looper myLooper() {

        returnsThreadLocal.get();

}

原来就是获取之前说的sThreadLocalset进去的Looper实例,一个线程对应一个LOOPER实例,没得选咯,只能获取到初始化Handler方法的那个线程对应的Looper实例了。

接下来就是获取到Looper对应的MessageQueue对象。

 

下面sendMessageà sendMessageDelayedà sendEmptyMessageAtTime,就是这个咯。

 

 

  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;

}


      msg.target = this;这里就把自己实例赋值给了msg.target,

同时enqueueMessage  Message实例塞进了MessageQueue,链表实现的哦,这里不做详细介绍。

之前在Looper.looper中看到了

msg.target.dispatchMessage(msg);

 

看看这段源码:

    publicvoid dispatchMessage(Message msg) {

        if (msg.callback != null) {

            handleCallback(msg);

        } else {

            if (mCallback != null) {

                if (mCallback.handleMessage(msg)) {

                    return;

                }

            }

            handleMessage(msg);

        }

}


这里暂时不讨论Message以及Handler所给出的CallBack接口,

 

handleMessage(msg);便是我们自己所重写的那个方法。

这样一来,整个消息循环机制流程就清楚。

归纳下,如果我们从简单入手,就知道在UI线程中,已经为我们初始化了一个主Looper实例,归属于主线程(UI线程),接下来,Looper.loop()在该线程中就一直不断的循环,dispathMessage,分发消息。

HandlersendMessage其实就是把Message塞到了对应线程对应的Looper实例的那个MessageQueue中,然后捏,dispathMessage其实就是分发该消息,同时可以由自己的重写的hanleMessage方法来获取,做对应的工作。

当然,在非UI线程消息机制也是一样的道理,此处不详述咯

 

随笔随笔,估计会有很多不足以及错误的地方,希望大家能帮忙指正,谢谢各位看官。

 

原创作品,转载请注明http://blog.csdn.net/vc_player/article/details/7876762

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值