Handle、Loop、Message、MessageQueue 源码解析

首先感谢在看的读者们,因为这是我第一次写博客,可能写的不太好,大神勿喷、大神勿喷、大神勿喷。

好了废话不多说,下面进入我们的正题。

下面请看源码。。。。。。


===

『眼镜都带上了,楼主就让我看这个呀』

哈哈,当然不是呀。我只是想说 所有学习的东西都是从 hellow world 开始,所以写了一个大大的Hellow world,酝酿一下。

首先我们都知道每一个app的入口都是main方法开始运行,那说啥,咱们点击去看一下把

main方法是放在final 修饰的ActivityThread类中。代码如下:

public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
我们先看一下第一行代码 
Looper.prepareMainLooper();

这行代码就是准备ui线程的Looper。 可能大家有个疑问,平时我们创建Loop对象就是通过Looper.prepare();进行创建。

他俩有什么区别呢?

主要区别在于他们方法里面都调用了prepare(boolean quitAllowed) 方法,只是传值不一样。我们点击进去看看。quitAllowed最后赋值给mQuitAllowed参数。 

void quit(boolean safe) {
        // 如果主线程退出抛出异常
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }
        //下面的if语句防止同步问题
        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;
            //safe 是否选择安全退出模式
            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }

好了,看了上面的代码,我们明白了它两者的区别了吧。prepareMainLooper方法和prepare方法区别在于是否允许Looper.loop() 结束循环

如果想退出循环调用 Looper.myLooper().quit();或者Looper.myLooper().quitSafely(); 

接下来,我们看一下Looper.prepare();方法是怎么创建Looper的

private static void prepare(boolean quitAllowed) {
    //通过下面的3行代码,我们可以准确的确定一个线程中只能有一个Looper对象
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
     //把创建出来的Looper放入ThreadLocal静态常量中
     sThreadLocal.set(new Looper(quitAllowed));
 }

sThreadLocal.get() 方法实现方式类似于hashmap的实现原理 根据当前线程得到一个ThreadLocalMap静态内部类,判断是否为空,不为空在通过getEntry得到Entity对象,然后通过.value得到当前的Looper。

sThreadLocal.set(new Looper(quitAllowed)) 根据当前线程得到一个ThreadLocalMap静态内部类,判断是否为空,不为空重新设置(修改或者添加),为空则创建。
//new Looper()构造方法中
private Looper(boolean quitAllowed) {
        //创建Looper 的时候同时也创建了一个MessageQueue对象。我们可以的出一个结论:一个线程只有一个Looper对象 一个Looper也只有一个MessageQueue对象
        mQueue = new MessageQueue(quitAllowed);
        //得到当前线程
        mThread = Thread.currentThread();
}

从上面的代码我们能看到Looper、MessageQueue的关系。Looper.prepare()的时候会创建一个Looper对象放入ThreadLocal中,同时创建looper的时候,也创建了MessageQueue对象。

接着我们看下Handler是怎么把Message放入MessageQueue

首先Handler 发送消息是通过sendMessage方法

sendMessage调用了sendMessageDelayed方法,sendMessageDelayed方法调用sendMessageAtTime方法

在sendMessageAtTime 我们可以看到得到了一个MessageQueue对象,然后在调用enqueueMessage方法传入MessageQueue和Message。方法中Message设置target为创建好的Handler对象,然后MessageQueue通过enqueueMessage把Message添加到自己的队列中,代码如下。

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

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

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {

        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }

        return queue.enqueueMessage(msg, uptimeMillis);
 }
剩下的任务就交给了Looper.loop() 主要代码如下:
public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            ......
            final long end;
            try {
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
           ......
        }
    }

代码首先通过myLooper()方法得到了一个Looper对象 ,而myLooper()方法其实调用了sThreadLocal.get()方法,把之前保存好的Looper对象取出来。得到Looper对象后,在把Looper对象里面的MessageQueue得到。

接着for循环开始,queue.next()方法不断从MessageQueue中拿出Message信息,然后通过之前设置好的target值进行dispatchMessage方法会调发送给Ui线程 进行更新ui操作。

其实细心的同事可以看到dispatchMessage回调时候还会执行handleMessage方法。在这里就不细说了。代码很简单,点击去看看就明白了。

下面做一下总结:

程序启动的时候默认会创建一个Looper对象和MessageQueue对象

Handler发送消息的时候,会把Message信息保存到MessageQueue中,并设置target为当前的Handler

最后Looper.loop() 方法把MessageQueue里面的Message信息取出来,得到Message里面的target,调用dispatchMessage()把Message传入,更新UI线程

面试问题总结:

Android使用Handler实现子线程与子线程、主线程之间通信



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值