android消息,聊聊Android的消息机制

Android的消息机制主要是指Handler的运行机制和它所附带的MessageQueue和Looper的工作过程。

Handler、MessageQueue和Looper这三者其实是一个整体。但是我们要想清楚这个整体的工作流程就需要逐个击破。

下图罗列了这次分享说的重点

c84c60cb7130

Android的消息机制.png

一、为什么提供这种机制

系统之所以提供这种机制主要是为了解决在子线程不能访问UI的矛盾。

那么问题来了......

1.为什么子线程不能访问ui呢?

因为Android的ui控件不是线程安全的。如果在多线程的情况下并发访问就会导致ui控件处于不可预期的状态。

2.那么在这种情况下为什么不对ui控件的访问加上锁机制呢?

首先加上锁的机制会使访问ui控件的逻辑变得复杂,其次因为锁机制会阻塞某些线程的进行,从而降低UI访问的效率。基于这两个原因最好的办法就是使用单线程处理UI控件。反之对于开发者来说只需要利用Handler切换一下线程就可以了,也不是很麻烦

二、MessageQueue(消息队列)

Android的消息队列是MessageQueue,它主要有两个功能:插入和读取。

它的内部实现是并不如它名字那样是个队列,而是用一个单链表来维护消息列表,我们知道单链表的数据结构实现插入和删除的效率高。

插入的操作很简单,本质就是单链表的插入操作。

//MessageQueue的插入操作 -enqueueMessage方法

boolean enqueueMessage(Message msg, long when) {

......

synchronized (this) {

......

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;

}

}

......

}

读取的操作next方法,通过无限的循环来检查有没有新消息,当有新消息来的时候,next方法会返回这条消息并将其从单链表中移除。

//MessageQueue的读取操作(伴随着删除操作)-next方法

Message next() {

......

synchronized (this) {

......

// Try to retrieve the next message. Return if found.

final long now = SystemClock.uptimeMillis();

Message prevMsg = null;

Message msg = mMessages;

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

// Stalled by a barrier. Find the next asynchronous message in the queue.

do {

prevMsg = msg;

msg = msg.next;

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

}

.....

}

三、ThreadLocal的工作原理

ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据和读取数据。

它的特点通俗点说就是,不同的线程访问同一个对象,它们通过ThreadLocal获得的值是不一样的。

还可以这么神奇?

首先它是一个泛型类

public class ThreadLocal {}

其次通过set方法我们可以看到它使用了Map的数据结构,它的key就是线程,value就是该对象的值。

//获取到当前线程的该变量的值,如果没有则初始化一个。

public void set(T value) {

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);

if (map != null)

map.set(this, value);

else

createMap(t, value);

}

set方法将线程对应的值进行存储

之后,通过get方法就可以获取到该对象在这个线程中的值。

public T get() {

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);

if (map != null) {

ThreadLocalMap.Entry e = map.getEntry(this);

if (e != null) {

@SuppressWarnings("unchecked")

T result = (T)e.value;

return result;

}

}

return setInitialValue();

}

最后抛出一个问题

为什么通过ThreadLocal可以在不同的线程中维护一套数据的副本并且互不干扰?

因为不同的线程访问同一个ThreadLocal的get方法,ThreadLocal内部会从各自的线程中取出一个数组,然后再从数组中根据当前的ThreadLocal的索引去查找对应的value值,这样不同的线程中取出的数组自然是不同的。简单的说就是它们所对ThreadLocal的读写操作仅限于各自的线程内部。

四、Looper的工作原理

我们知道,Handler的工作需要Looper,没有Looper的线程就会报错。

那么Looper是做什么的呢?

具体来说,就是不停的从MessageQueue中查看是否有新的消息,如果有消息就会立刻处理,否则就一直阻塞在那里等待新的消息。

如何为线程创建Looper?

很简单,通过Looper.prepare就可以为线程创建一个Looper,这样这个线程就有了属于他的Looper。之后调用Looper.loop()就可以开启消息循环。

Looper最重要的就是loop方法,它的工作原理也很简单,首先它是一个死循环,会调用MessageQueue的next方法不断的获取新的消息并处理,没有消息的时候就会阻塞在那里。直到Looper调用quit或者quitSafely方法。也就是说我们最后是要在合适的时候退出Looper的。否则就会一直循环下去。

五、Handler的工作原理

Handler的工作主要包含消息的发送和接收。

1.发送消息主要通过post和send的一系列方法实现

mHandler.postDelayed(runnable,0);

发送消息的过程只是向MessageQueue中插入一条消息,它的next方法就会把这条消息返回给Looper,Looper收到消息后就开始处理了。最终消息由Looper交由Handler处理。由于Looper里面使用了ThreadLocal,所以它就能够将消息切换到指定的线程中执行。

2.处理消息

Looper将消息交由Handler处理,就会调用Handler的disaptchMessage方法。这时候就进入了处理消息的阶段。

/**

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

}

}

首先,检查Message的callback是否为null,不为null就通过handleCallback处理消息。这个callback是一个Runnable对象,也就是我们在post方法里传递的Runnable参数。

其次检查mCallBack是否为null,不为空就调用handleMessage方法。CallBack是一种当我们不想通过派生子类创建Handler的另外一种实现方式。

最后调用Handler的handlerMessage来处理消息

到这里我们就聊完了Android的消息机制,它的作用就是很轻松的将某个任务或者说是消息切换到指定的线程(Handler所在的线程)中执行。本质上来说,它并不是专门用于更新UI,只是常常被用在更新UI上。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值