1. Android 进程和线程
- 四大组件并不是程序(进程)的全部,只是它的“零件”
- 应用程序启动后,将创建 ActicityThread 主线程。
- 同一个包中的组件将运行在相同的进程空间中。
- 不同包中的组件可以通过一定的方式运行在一个进程空间中。
- 一个 Activity 应用启动后至少有3个线程:一个主线程,2个Binder 线程。
2. Handler MessageQueue Runnbale 和 Looper
-
Looper 循环地去做某件事情
不断地从 MessageQueue 中取出一个 item, 然后传给 Handler 进行处理,如此循环往复。如果队列为空,那么它会进入休眠。
-
Handler 是真正处理事情的地方。
利用自身的处理机制,对传入的各种 Object 进行相应的处理并产生最终的结果。
Looper 不断获取 MessageQueue 中的一个 Message ,然后由 Handler 来处理。
2.1. Handler
// framework/base/core/java/android/os/Handler.java
public class Handler {
...
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
}
- 每个 Thread 只对应一个 Looper
- 每个 Looper 只对应一个 MessageQueue
- 每个 MessageQueue 中有 N 个 Message
- 每个 Message 中最多指定一个 Handler 来处理事件 (多了就乱了)
Thread 和 Handler 是一对多的关系
Handler 主要作用:
- 处理 message
- 将某个 message 压入 MessageQueue 中 (这也是处理 message 的一种方式)
public void dispatchMessage(Message msg); // 对 Message 进行分发
public void handleMessage(Message msg); // 对 Message 进行处理
Looper 从 MQ 中取出一个 Message 后,首先会调用 Handler.dispatchMessage 进行消息的派发。
默认情况下 Handler 的派发流程:
- Message.callback (Runnable 对象) 是否为空
在不为空的情况下,将优先通过 callback 来处理 - Handler.mCallback 是否为空
在不为空的情况下,调用 mCallback.handleMessage - 如果前两个对象都不存在,才调用 Handler.handleMessage
Handler 的扩展子类可以通过重载 dispatchMessage 或者 handleMessage 来改变它的默认行为。
post 和 send
两者都是负责将某个消息压入 MessageQueue 中,区别在于 send 处理的函数参数是 Message, 而 post 则需要先把其他类型的 "零散" 信息转换成 Message,再调用 Send 系列函数来执行下一步。
因为调用者提供的是 Runnable 对象,post 需要先将其封装成一个 Message, 接着通过对应的 send 函数把它推送到 MessageQueue 中。
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain(); // 1
m.callback = r; // 这里将 runnable 对象设置成 Message的回调函数
return m;
}
// 1 中,Android 系统会维护一个全局的 Message 池,当用户需要使用的时候,可以通过obtain直接获得,而不是自行创建。这样的设计可以避免浪费资源。
Loop 中包含了一个 MessageQueue 。
现在就可以看成 Looper 和 Handler (隐藏的 Thread) 之间的关系了。
应用程序使用 Looper 有两种情况:
1. 主线程(MainThread) : 也就是 ActivityThread
1. 普通线程
普通线程范例:
1. Looper 的准备工作(prepare)
2. 创建处理消息的 Handler
3. Looper 开始运作(loop)
问题:
- Looper 对象怎么创建的?
- mHandler 是怎么保证把外部的消息投递到 Looper 管理的 MessageQueue 中的?
- Looper 和 Handler 之间有什么隐藏的联系?
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare(); // 1.Looper 的准备工作
mHandler = new Handler() {
public void handleMessage(Message msg) {
...// 处理消息的地方,继承 Handler 的子类通常需要修改这个函数
}
};
Looper.loop();// 进入主循环
}
}
这里的 Looper.prepare()
import android.os.Looper;
......
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
这是一个静态类型的变量,意味着一旦 import 了 Looper 后,sThreadLocal 就已经存在并构建完毕。
ThreadLocal 对象是一种特殊的全局变量,只限于自己所在的线程,外界的线程(哪怕是同一进程)都无法访问到它。每个线程的 Looper 是独立的。
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));
}
sThreadLocal.get() 返回的是模板类,这个场景中是Looper.
mQueue 是Looper 和 Handler 之间的沟通桥梁。
// frameworks/base/core/java/android/os/Looper.java
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
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));
}
sThreadLocal 会创建一个只针对当前线程的 Looper以及其他相关的数据对象。sThreadLocal.get() 返回的是模板类,这个场景中是Looper。
上面我们看到 mHandler 是 LooperThread 的成员变量,并通过 new 操作创建了一个 Handler 实例。
Handler 有如下内部变量需要初始化:
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
public Handler() {
...
mLooper = Looper.myLooper();
...
mQueue = mLooper.mQueue; // 就是 Looper中的 mQueue
mCallback = null;
}
// frameworks/base/core/java/android/os/Looper.java
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
这样 Handler 、Looper、MessageQueue 就联系起来了,后面 Handler 执行 Post/Send 两个系列函数时,会将消息投递到 mQueue(mLooper.mQueue) 中,一旦 Looper 处理到这一消息,又会从中调用 Handler 来进行处理。
3. UI 主线程 - ActivityThread
framework/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
...
Looper.prepareMainLooper(); // 和之前的 LooperThread 不同
ActivityThread thread = new ActivityThread(); // 新建一个ACthread对象
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler(); // 主 Handler
}
AsyncTask.init();
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
-
prepareMainLooper 和 prepare
普通线程只要 prepare 就可以了,而主线程使用的是 prepareMainLooper
-
Handler 不同
普通线程生成一个与 Looper 绑定的 Handler 对象就行,而主线程是从当前线程中获取的 Handler(thread.getHandler);
1. prepareMainLooper 有什么特殊之处呢?
public static void prepareMainLooper() {
prepare(false); // false 表示该线程不允许退出
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
和前面一样,经过 prepare 之后会, myLooper() 就可以得到一个本地线程 的 Looper 对象然后将其赋给 sMainLooper。
线程1不能直接访问到线程2中的 Looper 对象,但二者都可以接触到进程中的各元素。
线程1: 因为是 main Thread , 使用的是 prepareMainLooper ,这个函数将通过 prepare 为线程1生成一个 ThreadLocal 的 Looper 对象,并让 sMainLooper 指向它。这样的目的就是其他线程如果要获取主线程的 Looper, 只需要调用 getMainLooper 即可。
线程2: 作为普通线程,调用的是 prepare(), 同时也生成了一个 ThreadLocal 的 Looper 对象,只不过这个对象只能在线程内通过 myLooper() 访问。
当然,主线程也能通过 myLooper 这个函数来访问它的 Looper 对象。
这里,区分开了各个线程的 Looper, 并界定了他们的访问权限。
2. sMainThreadHandler
当 ActivityThread 对象创建的时候,会在内部同时生成一个继承自 Handler 的 H 对象。
final H mH = new H();
ActivityThread.main 中调用的 thread.getHandler() 返回的就是 mH, 提供了一个事件管家,来处理主线程中的各种消息。
loop( ) 函数
public static void loop() {
// loop 函数也是静态的,所以它只能访问静态数据。
// 函数myLooper 则调用 sThreadLocal.get() 来获取与之匹配的 Looper 实例
// 其实就是取出之前 prrpare 中创建的那个 Looper 对象。
final Looper me = myLooper();
...
// Looper 中自带一个 MessageQueue
final MessageQueue queue = me.mQueue;
...
for(;;) { // 消息循环开始
Message msg = queue.next(); // 从 MessageQueue 中取出一格消息,可能会阻塞
if (msg == null) {// 如果当前消息队列中没有 msg, 说明线程要退出了。
return;
}
...
// 开始分派消息,target 是一个 Handler
msg.target.dispatchMessage(msg);
...
msg.recycle(); // 消息处理完毕,进行回收
loop 的主要工作就是不断地从消息队列中取出需要处理的事件,然后分发给相应的责任人
如果消息队列为空,它很可能会进入睡眠以让出 CPU 资源。在具体事件的处理过程中,程序会 post 新的事件到队列中。另外,其他进程也可能投递新的事件到这个队列中。
APK 应用程序就是不停地执行“处理队列事件”的工作,直到它退出运行。
ActivityThread 这个主线程从消息队列中取出 Message 后, 调用它对应的 Runnable.run 进行具体的事件处理。处理过程中还会涉及到其他类的调用。它们可能还会向主循环投递新的事件来安排后续的操作。
另外,其他进程也可以通过 IPC 机制这一进程的主循环发送新事件,如触摸、按键事件等,这就是 APK 应用程序动起来的原因。
插曲:MessageQueue 的创建
final MessageQueue mQueue;
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread(); // Looper 与当前线程建立对应关系
好的,本篇文章的主要内容就是这么多了,喜欢的话请帮忙点赞、收藏、转发,最后给我一个大大的关注!我是樱木Plus, 一名android开发者。我们下期再见。