一、概序
Android 消息机制原理解析。关于 Android 消息机制的使用,大家一个想到的就会是在子线程中更新控件,确实,安卓设计出这个机制很大一部分原因是处于这个目的,但是并不是全部。本篇文章,作者也会从源码的角度去分析消息机制的运作方式,希望大家能从文章中了解到消息机制的使用方法以及它为什么能被这样用。
二、Android 消息机制
首先我们来看一下平常使用消息机制的方式:
- public class MainActivity extends AppCompatActivity {
- private Button button; // 初始化handler private Handler handler = new Handler() { @Override public void dispatchMessage(Message msg) { // 收到消息后要做的事情,例:更新UI // 对应发送方式(1) button.setText("get msg"); switch (msg.what) { case 0: break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.bt); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 发送方式(1) // 这个方法中的参数就对应了Message中的what变量 handler.sendEmptyMessage(0); // 发送方式(2) Message msg = new Message(); Bundle bundle = new Bundle(); msg.setData(bundle); handler.sendMessage(msg); // 发送方式(3) Runnable runnable = new Runnable() { @Override public void run() { // 线程中要做的事情 } }; handler.post(runnable);// 正常发送 } }); }}
使用方式很简单,就像我们平时使用时在子线程里面更新 UI 一样。这里我列举了三种常用的推送消息的方式,其实无论是那种方式,最终都会调用到 Handler 的 sendMessageAtTime() 方法。
发送方式一:
- 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 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 final boolean sendMessageDelayed(Message msg, long delayMillis) {
- if (delayMillis < 0) {
- delayMillis = 0;
- }
- return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
- }
- private static Message getPostMessage(Runnable r) {
- Message m = Message.obtain();
- m.callback = r;
- return m;
- }
这里推送方式三说一下,虽然推送消息时要放一个 Runnable 对象进去,有点像是异步处理一样,但是其实不是的,这个 runnable 对象会通过 getPostMessage() 方法设置称 message 对象的回调,然后在 handler 处理消息的时候会判断这个回调是否为空,不为空的话就会执行这个回调
接下来我们来看一下消息机制中几个关键的类
MessageQueue
MessageQueue 实际上不是队列,而是用链表的形式实现的,因为链表更适合于插入 / 删除操作。它主要做了两件事情:
1. enqueueMessage() 方法向链表中插入一条 Message
2. next() 方法返回 Message 并在链表中将它删除
- /** * next主要做的事情就是:开启一个死循环不断读取消息,如果队列中没有消息就会一直阻塞 */
- Message next() { // 一段算法代码 ...}/** * 把message插入到messageQueue中 */boolean enqueueMessage(Message msg, long when) { // 一段算法代码 ...}
Message
Message 就是数据的载体,是 MessageQueue 里存放的基本单元。它实现了 Parcelable 的,代表他支持跨进程通信。看一下 Message 中几个重要的参数:
- // 先前介绍的handler三种使用方式中的使用方式(2)用到了的BundleBundle data;// message对应的HandlerHandler target;// 先前介绍的handler三种使用方式中的使用方式(3)用到了的BundleRunnable callback;// 当前msg的下一个msgMessage next;// 当前的msg,static修饰的Message sPool;
然后看一下 obtain 方法,Message 中重载了很多个 obtain 方法,并且最终都会调用同一个方法但是他们的作用是同一个:给参数赋值。
- public static Message obtain() {
- synchronized(sPoolSync) {
- if (sPool != null) {
- Message m = sPool;
- sPool = m.next;
- m.next = null;
- m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message();}
Looper
先看一下它的构造方法
- private Looper(boolean quitAllowed) {
- mQueue = new MessageQueue(quitAllowed);
- mThread = Thread.currentThread();
- }
构造方法做了两件事情:
1. 创建一个 MessageQueue 对象
2. 把当前线程赋值给变量 mThread
要给一个线程创建 Looper 必须在线程中调用 prepare() 方法,UI 线程的 Looper 由安卓系统在调用 prepareMainLooper() 生成。
- public static void prepare() {
- prepare(true);
- }
- private static void prepare(boolean quitAllowed) {
- if (sThreadLocal.get() != null) {
- throw new RuntimeException("Only one Looper may be created per thread");
- }
- sThreadLocal.set(new Looper(quitAllowed));
- }
- /** * Initialize the current thread as a looper, marking it as an * application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself. See also: {@link #prepare()} * 翻译一下:初始化当前线程的looper,标记它为主线程的looper,软件主线程的 looper是由android系统创建的,所以你永远都不要自己调用这个方法。 * 这里还有个prepareMainLooper()方法,用于给Main线程创建looper。 */
- public static void prepareMainLooper() {
- prepare(false);
- synchronized(Looper.class) {
- if (sMainLooper != null) {
- throw new IllegalStateException("The main Looper has already been prepared.");
- }
- sMainLooper = myLooper();
- }
- }
从上面代码可以看出来,每个 Thread 只能创建一个对应的 Looper。
再来看一个 Looper 中最重要的 loop() 方法:
- /** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end theloop. * 翻译一下:运行当前线程的messageQueue,可以通过quit()方法来停止loop()方法 */
- public static void loop() { // 开启一个无限的循环 for (;;) { // 从queue中取出一个msg Message msg = queue.next(); // might block if (msg == null) { // 如果msg为空,毛也不做 return; } } // 一段我们不需要关心的代码 ... try { // 这里的msg.target其实就是msg对应的Handler msg.target.dispatcMessage(msg); } finally { if (traceTag != 0){ Trace.traceEnd(trceTag); } } // 一段我们不需要关心的代码 ...}
loop 方法里面开启了一个无限的循环,循环中不断的从 messageQueue 中读取 message,然后把 message 丢给对应 handler 处理。
vcHLyuzPpLXESGFuZGxlcsHLo6zWrsv50tSw0UhhbmRsZXK3xbW91+6686OsysfS8s6qSGFuZGxlctbQy/nX9rXEysLH6ba8ysfJ2bK7wcvHsMPmvLi49sDgtcSjrEhhbmRsZXK4/LbgtcTKx9K7uPa0psDtz/vPorXEvcfJq6GjztLDx8/ItNPL/LXEubnU7Le9t6i/tMbwOjwvcD4NCjxwcmUgY2xhc3M9"brush:java;">public Handler(Callback callback, boolean async) {// 一段我们不是很关心的代码 ... // 获取当前 Handler 的 Looper 对象,如果为空会抛出异常没有调用 Looper.prepare() 方法 mLooper = Looper.myLooper(); if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()"); } // 获取 Looper 对应的 MessageQueue mQueue = mLooper.mQueue; // 设置回调 mCallback = callback; mAsynchronous = async;}
在文章的开篇我们介绍了 handler 几种发送消息的方法,它们最终都会调用 sendMessageAtTime() 方法
- public boolean sendMessageAtTime(Message msg, long uptimeMillis) { // 设置handle的messageQueue 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); } // 把消息插入到messageQueue中 return queue.enqueueMessage(msg, uptimeMillis);}
介绍了这么多,我们来总结一下:
1. 每个线程只能拥有一个 Looper,通过 Looper 的 prepare() 方法生成。
2. Looper 生成时会新建对应的 MessageQueue。然后 Looper 中最重要的方法是 loop(),它做的事情是:开启一个死循环不断从 MessageQueue 中读取消息然后交给 Handler 处理
3. Handler 是处理消息的角色
上一张简单粗暴的流程图:
在使用 handler 在子线程中更新 UI 时需要注意的一点就是,Handler 必须要在 UI 线程中实例化,其实原因通过文章上面的内容已经可以很好的解释了,在子线程中更新 UI 其实说到底还是在 UI 线程更新 UI,因为你只是在子线程中 post 了一个消息而已,而获取到消息后真正更新 UI 的地方还是在实例化 Handler 的线程中,我们来做一下实验就知道了:
- public class MainActivity extends AppCompatActivity {
- private Button button;
- private Handler handler;@Override protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- button = (Button) findViewById(R.id.bt);
- new Thread(new Runnable() {@Override public void run() {
- Looper.prepare();
- handler = new Handler() {@Override public void dispatchMessage(Message msg) { // 收到消息后要做的事情,例:更新UI button.setText("get msg"); } }; Looper.loop(); } }).start(); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { handler.sendEmptyMessage(0); } }); }}
Handler 机制在 android 源码中有很多地方都用到了,希望大家通过这篇文章对安卓的消息机制有一个比较清楚的了解
。
就爱阅读 www.92to.com 网友整理上传, 为您提供最全的知识大全, 期待您的分享,转载请注明出处。
来源: http://www.92to.com/bangong/2017/04-01/19780000.html