Android的消息机制几乎是面试必问的话题,当然也并不是因为面试,而去学习,更重要的是它在Android的开发中是必不可少的,占着举足轻重的地位,所以弄懂它是很有必要的。下面就来说说最基本的东西。

Looper

作用:

  • 关联起Thread
  • 循环取出消息

1、Looper是否可以直接实例化?

Looper构造方法是私有的,其中做了两件事

  • 创建一个MessageQueue
  • 得到与之对应的Thread
 private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

2、一个线程能对应多个Lopper?

不能,一个线程对应一个Looper对象,通过ThreadLocal保证一个线程只有一个Looper与之对应,如果多次调用Looper.prepare();则会抛出运行时异常。

 private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) { // 查看是否有looper与当前线程对应
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}

3、Looper是无限循环,会阻塞吗?

是,当开启一个loop后是一个死循环,从MessageQueue中取出消息,处理消息,但是也有可能退出,在没有消息后退出循环。

  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;
}
// 略
msg.target.dispatchMessage(msg);
}

4、可以再次调用Looper.prepareMainLooper吗?

不可以,Looper.prepareMainLooper最终也是调用prepare(),同2.

public static void prepareMainLooper() {
prepare(false); // 创建一个Looper
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}

5、MainLooper什么时候创建的?

MainLooper是启动Activity创建ActivityThread(并不是一个Thread)时候创建,所以不能多次创建。

public static void main(String[] args) {
// 略
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
// 略
ActivityThread thread = new ActivityThread();
thread.attach(false);
// 略
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
} // 略
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
}

Handler

作用:

  • 发送消息到MessageQueue
  • 处理消息

1、Handler如何与Looper、MessageQueue关联起来?

我们知道一个Looper对应一个Thread,一个Looper包含一个MessageQueue。当我们创建Handler时就会从当前线程中取出与之对应的Looper,让后在从Looper中取出MessageQueue。

// 1、自动获取
public Handler(Callback callback, boolean async) {
// 略
mLooper = Looper.myLooper(); // 取出当前线程中的Looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; // 取出MessageQueue
mCallback = callback;
mAsynchronous = async;
}
// 2、传递一个Looper进来
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

Message

单项链表结构。

作用:

  • 数据的载体

1、消息如何复用的?

从全局消息池(链表结构)中

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

2、Message为什么能传递?

Android中想要传递对象要么实现Serializable要么Parcelable,在这里是实现了Parcelable接口。

public final class Message implements Parcelable {
// 略
}

3、如何与Handler关联?

我们知道在消息传机制中Handler充当着“快递员”的角色,那么他又是如何与“货物”--Message发生关系呢?实际上Message有一个成员变量target他的类型正是Handler,

/*package*/ Runnable callback;

public int arg1; 

public int arg2;

public Object obj;

/*package*/ Handler target; // 关键点

当我们通过Handler去send一个Message时候最终都会为target赋值为this,即当前的Handler。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; // 赋值语句
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}

另为如果是通过Message.Obtain(),获取的复用Message也会为其赋值。

多说一句,Handler.obtainMessage()调用的就是Message.Obtain()。

public final Message obtainMessage(){
return Message.obtain(this);
}

总结:

通过一系列的包涵关系,最终Looper、Handler、Message、MessageQueue即发生关联,从而形成一个闭合,开启消息循环。

困惑

【转载】每个 Android 开发者必须知道的消息机制问题总结的更多相关文章

  1. (转载)Android开发者必知的开发资源

    (转载)http://www.importnew.com/3988.html 随着Android平台市场份额的持续猛增 ,越来越多的开发者开始投入Android应用程序的开发大潮.如果您是一位2013 ...

  2. Android 面试收集录5 消息机制

    1.消息机制概述 1.1.消息机制的简介 在Android中使用消息机制,我们首先想到的就是Handler. 没错,Handler是Android消息机制的上层接口. Handler的使用过程很简单, ...

  3. android 进程/线程管理(四)----消息机制的思考(自定义消息机制)

    关于android消息机制 已经写了3篇文章了,想要结束这个系列,总觉得少了点什么? 于是我就在想,android为什么要这个设计消息机制,使用消息机制是现在操作系统基本都会有的特点. 可是andro ...

  4. [Android]简略的Android消息机制源码分析

    相关源码 framework/base/core/java/andorid/os/Handler.java framework/base/core/java/andorid/os/Looper.jav ...

  5. 深入理解 Handler 消息机制

    记得很多年前的一次面试中,面试官问了这么一个问题,你在项目中一般如何实现线程切换? 他的本意应该是考察 RxJava 的使用,只是我的答案是 Handler,他也就没有再追问下去了.在早期 Andro ...

  6. Android开发系列之事件拦截机制

    对于Android开发者来说理解事件传递机制的重要性,我想应该是不言而喻的.在一个Activity里面,我们经常会重写onTouchEvent事件,可是重写结束之后,对于是返回true还是返回fals ...

  7. [转载]Android开发者必须深入学习的10个应用开源项目

    [转载]Android开发者必须深入学习的10个应用开源项目 原文地址:Android开发者必须深入学习的10个应用开源项目(http://blog.sina.com.cn/s/blog_7b8a63 ...

  8. Android 高级UI设计笔记08:Android开发者常用的7款Android UI组件(转载)

    Android开发是目前最热门的移动开发技术之一,随着开发者的不断努力和Android社区的进步,Android开发技术已经日趋成熟,当然,在Android开源社区中也涌现了很多不错的开源UI项目,它 ...

  9. 【原创】源码角度分析Android的消息机制系列(一)——Android消息机制概述

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 1.为什么需要Android的消息机制 因为Android系统不允许在子线程中去访问UI,即Android系统不允许在子线程中更新UI. 为什 ...

随机推荐

  1. google跟踪代码管理器gtm无法给相同class元素绑定click事件埋点解决

    Google 跟踪代码管理器是一个跟踪代码管理系统 (TMS),可以帮助您快速轻松地更新网站或移动应用上的跟踪代码及相关代码段(统称为“代码”).将一小段跟踪代码管理器代码添加到项目后,您可以通过网页 ...

  2. Checklist for an RMAN Restore (Doc ID 1554636.1)

    Checklist for an RMAN Restore (Doc ID 1554636.1) APPLIES TO: Oracle Database - Enterprise Edition - ...

  3. Attaching an entity of type 'xxx' failed because another entity of the same type already has the same primary key value.

    问题的详细描述: Attaching an entity of type 'xxxxx' failed because another entity of the same type already ...

  4. Linux IO协议栈

    图片来源自网络,保持更新:更多内容请关注 cnblogs.com/xuyaowen 参考链接: https://zhuanlan.zhihu.com/p/39721251 http://blog.yu ...

  5. DenyHosts

    下载软件并解压cd DenyHosts-2.6 #进入安装解压目录python setup.py install #安装DenyHostscd /usr/share/denyhosts/ #默认安装路 ...

  6. python3解决url编码与解码

    对于url编码的转换,主要用urllib.parse包中的quote和unquote方法. quote进行解码,unquote进行编码. 代码实例: import urllib.parse u = & ...

  7. 2个ajax的相互调用解决异步问题

  8. SSM 实现登录注册功能

    1.上一篇SSM框架搭建好了之后就要开始写功能了,现在来写一个简单的登录注册功能 这几个包是自己手动创建的,然后往里面写代码 2.代码详情 package com.maike.controller; ...

  9. php程序内存优化之数组操作优化

    一.前言这篇文章其实是上篇文章的内存优化部分.博主的php程序在执行的时候,报错: Out of memory (allocated 364904448) (tried to allocate 262 ...

  10. Xml之Schema XSD约束{详细}

    问题: 学习Schema其他标签的定义 约束 引入的方式: 基本格式: 1构建schema: 1.1 最基本的单位元素 1.2 元素属性 1.3 simpleType 定义类型 1.4 复合结构类型 ...