进程是应用程序的一个运行活动过程,是操作系统资源管理的实体,也就是操作系统分配资源的最小单元,比如系统内存、代码、数据、CPU时间片等资源,为正在运行的应用程序提供运行环境。 每个进程都有自己独立的资源和内存空间,其它进程不能任意访问当前进程的内存和资源,并且系统给每个进程分配的内存会有限制。
线程是进程内部执行代码的实体,它是CPU调度资源的最小单元,一个进程至少包括一个主线程(进程被操作系统创建,时一个主线程也立刻运行,它无需由用户去主动创建)。线程没有自己独立的内存资源,它只有自己的执行堆栈和局部变量,所以线程不能独立地执行,它必须依附在一个进程上。也就是说进程只是提供一个环境和资源,或者说进程像容器一样提供了一个空间,里面包含了很多资源,线程等,真正执行代码的地方是在线程里。多个线程共享一块内存空间和一组系统资源,所以系统在各个线程之间切换时,资源占用要比进程小得多。
一个进程运行起来也就是主线程运行起来,一旦主线程运行终止了,进程也就随之终止,因此几乎任何操作系统和编程语言中,一旦程序运行起来就会进入一个死循环中,并在循环中处理各种事件,直到进程结束。那么在Android中也不例外,Android应用程序就是通过消息来驱动的,在主线程的死循环中,一旦有消息来就会取出消息执行对应的事件,如果没有消息,此时主线将会进入睡眠状态,因此消息循环并不会对CPU性能有过多的消耗。这种消息循环机制主要涉及到三个类,Handler,Looper,MessageQueue,下面将全面分析这几个类之间的协作关系。
消息机制的创建
四大组件的管理服务ActivityManagerService在启动一个应用程序组件时,如果发现这个组件所需要的应用程序进程还没有启动起来,那么它就会请求Zygote进程将这个应用程序进程启动起来,Zygote进程是通过复制自身的方式来创建一个新的应用程序进程的。
一个新的应用程序进程在创建后会初始化一些资源,比如获取一个虚拟机实例,一个Binder线程池等,接着会调用应用程序进程的入口函数,它就是ActivityThread类的静态成员函数main,在这个main方法中会为主线程创建一个消息循环。这样,运行在它里面的应用程序组件就可以方便地使用Android系统的消息处理机制,以及Binder进程间通信机制来实现自己的业务逻辑。
public final class ActivityThread {
......
public static void main(String[] args) {
......
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");
}
......
}
第5行代码首先调用Looper类的静态方法prepareMainLooper来创建一个消息队列,然后在第7行创建了该类的实例,并调用该类的实例方法attach来初始化一些资源,以及在
attach方法保存该类实例为一个静态变量,以便后面程序中使用,最后在14行调用Looper类的静态方法loop来开启消息循环。
至此,新进程的消息循环就创建完成,那么进程的启动过程也就完成了。
接下来我们来分析一下,Android线程消息队列的创建过程,也就是Looper类的prepareMainLooper()和prepare()方法的实现,下面列出的是Looper类的主要实现。
public final class Looper {
......
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
......
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));
}
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
public static void loop() {
......//下面分析
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
public static @NonNull MessageQueue myQueue() {
return myLooper().mQueue;
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
......
}
第8行代码prepareMainLooper()方法首先会调用prepare()方法来创建一个
Looper对象
,并将Looper对象保存在sThreadLocal变量中,
sThreadLocal代表当前线程
。在
Looper的构造方法中,会创建一个消息队列MessageQueue,以及将当前所在的线程对象保存在mThread变量中。
在调用
prepare()方法时传入
的false最终会传给MessageQueue,false代表主线程的消息循环不能够调用quit方法来退出。
public final class MessageQueue {
// True if the message queue can be quit.
private final boolean mQuitAllowed;
@SuppressWarnings("unused")
private long mPtr; // used by native code
private boolean mQuitting;
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
......
}
在MessageQueue的构造方法中,将Looper传递过来的参数false保存在mQuitAllowed变量中,从第15行的quit()方法中可以看出
主线程的消息循环不能够调用
quit方法来退出的。在构造方法中还调用了Native层中的nativeInit()本地方法,该方法在Native层创建了一个与MessageQueue对应的NativeMessageQueue对象,并返回该对象的指针给mPtr变量,这样
Java层的
MessageQueue对象和Native层的NativeMessageQueue对象建立了关联。其实,在Andrid 2.3以前,只能在Java层中向MessageQueue中添加消息以驱动Java世界的正常运转,但从Android 2.3开始,MessageQueue的核心部分下移至Native层,可以在Native层利用消息循环来处理他们所在世界的事情,所以在Native层也有对应的Looper,NativeMessageQueue及Handler类。
当消息队列MessageQueue创建完成后,消息机制还不能正常工作,最后还需要调用Looper类的loop()方法来开启消息循环,接下来我们来分析一下,Android线程消息循环的启动过程。
public final class Looper {
......
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;
}
......
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
......
msg.recycleUnchecked();
}
}
......
}
在loop()方法的第10行代码中,会获取Looper中创建的MessageQueue,随后开启一个for死循环,不断调用next()方法从
MessageQueue中获取要处理的消息,如果没有消息或者消息的处理时间没到,线程将会在第14行代码处睡眠,直到被唤醒。第15行代码判断当前返回的消息是否为空(null),为空一般会睡眠,而此处竟然返回消息,说明某处调用了MessageQueue的quit方法,此时就要退出线程消息循环。当获取到非空消息后会在第22行分发该消息来处理,处理完消息又回到第14行代码来获取下一个消息,如此循环,Android应用程序线程循环就是这样被消息驱动的执行业务的。