Android中的消息机制-源码分析

这个话题相信大家都不陌生,本人权当是一次比较系统的梳理。
Handler的几种消息发送方式
在Android中最常用的消息通信机制,即子线程和UI线程之间的通信,我们一般是基于Handler机制实现的,那么下面来看一看Handler的几种发送消息的方式。
1.sendMessage(Message message)
最常用的一种方式,下面我们一层层走下去。最后走到了sendMessageAtTime这个方法。我们见到了MessageQueue,相信大家也都知道,这就是传说中的那个消息队列,那么这个队列到底在哪初始化的呢?
假如我们使用的是new Handler()这个构造函数, 那么最终是调用Handler(Callback callback, boolean async)这个构造函数,可以看到这么行代码 mQueue = mLooper.mQueue,瞬间明朗,原来是Looper中的。(可参见Looper)
2.post(Runnable)
当我们在子线程中执行完之后,然后只想在执行一段代码块,二不需进行一些判断等操作时,我们可以使用该方法。sendMessageDelayed(getPostMessage(r), 0); 按照我们传统的理解,Handler发送消息,Looper取消息,那么现在这里居然没有消息,很奇怪哈。

private static Message getPostMessage(Runnable r, Object token) {
        Message m = Message.obtain();
        m.obj = token;
        m.callback = r;
        return m;
    }

你自己虽然没有取消息,但是系统已经帮你做了,并且还将你的Runnable放到了消息中
后面的流程就和普通的发送消息类似了,走到了enqueueMessage这步。
他有一行重要的代码msg.target = this;
3.在Handler的构造方法中自带CallBack

public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }

最后是这样的,mCallback = callback;

再看Looper
让我们一起来细细的研究一下Looper类中的几个方法。
大家都知道UI线程和我们自己线程的区别,这对待Looper上也是有差别的呢。prepareMainLooper方法说的很清楚了,在UI线程启动的时候,系统会主动为你准备好一个MainLooper,这也是我们为什么只需在子线程中将消息发送就可以了,而无需操心主线程中的Looper,但是,如果是我们往子线程中发送消息呢?那么我们就必须调用prepare方法了,他会执行这么一句代码sThreadLocal.set(new Looper(quitAllowed));(可参见ThreadLocal)

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

MessageQueue有了。
下面再看看Looper的loop()方法,当我们在子线程中调用完prepare()后,便调用该方法,相当于开启轮询器,重要的方法在这里 msg.target.dispatchMessage(msg);
那么这里msg.target就是刚才发送消息的Handler啊,是时候看看dispatchMessage了

public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

我们会先检查callback这个变量,如果我们是用过post方法处理的,那么就是有这个callback的,其实就是你放进去的Runnable,最后会走到这一步message.callback.run();
然后会检查有没有CallBack,通过方法3处理消息就会有这个CallBack,如果没有,才走handleMessage方法。
ThreadLocal是个什么玩意儿呢
上面的方法源码如下:

 public void set(T value) {
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values == null) {
            values = initializeValues(currentThread);
        }
        values.put(this, value);
    }

1.拿到当前线程
2.拿到当前线程中的ThreadLocal.Values对象
3.将value放进去,键值即为当前的ThreadLocal
那么,我们可以这样理解,在每一个线程中都维护了一个ThreadLocal.Values对象,他相当于一个
集合,用于保存一些引用,那么当我们调用Looper.prepare()时,实际上是new出了一个Looper,然后保存到了ThreadLocal中的Values中。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值