Android系统中提供了两种实现多线程的方式,首先是我们Android编程中非常眼熟的Handler,然后是AsyncTask异步类,本章将讲解Handler方式实现多线程。在本章正式开始前,我觉得有必要说一下Android为什么需要多线程。
其实Android中的多线程主要是用来避免ANR(ApplicationNot Responding),手机比较卡的同学可能会经常遇到这种情况,手机界面卡住没有响应了,过了一段时间,Android系统弹出一个对话框,显示”ApplicationNot Responding”并且让用户选择”wait”or “close”. 为什么会出现这种状况呢?这还要从Android的系统机制说起。
Android系统中,一个程序第一次启动,Android会同时启动一个对应的主线程(MainThread),主线程主要负责处理UI相关的事件,所以主线程又叫做UI线程。在Android开发中必须遵循单线程模型的原则:UI操作并不是线程安全的,并且这些操作必须在UI线程中执行,这与普通的java程序不同。但是,无可避免的UI线程中的一些操作会很耗时,如网络连接。Android系统的机制除了单线程模型的特点,还要求Activiy的最长执行时间不能超过5s,BroadcastReceiver的最长执行时间不能超过10s,否则就会出现之前提到的ANR。正因为如此,Android中的多线程也就应运而生了。如果在新开的线程中需要对UI进行设定,就可能违反单线程模型,因此android采用一种复杂的MessageQueue机制保证线程间通信。
Google在设计Android的消息循环机制的时候是参考了Windows程序的消息循环机制的,因此Android的应用程序的消息循环机制也是由消息循环、消息发送和消息处理三部分构成的。下面是Android消息循环机制的示意图。
图一Android消息循环机制的示意图
要理解Android的消息循环机制需要把握好下面这四个核心类:
(1) Looper, 消息循环器。它负责源源不断的依次从MessageQueue中取出消息,并将消息分发到指定的Handler对象进行处理。
(2) MessageQueue, 消息队列。它是被封装在Looper中的,接受Handler发来的消息,按照FIFO规则执行,等待Looper的抽取。
(3) Handler, 消息的发送者和处理者。 每个Handler在创建时都被绑定到一个Looper,它把消息发送到与它绑定的Looper的消息队列中。
(4) Message, 消息类。它封装了消息的相关内容。包括消息ID,消息处理对象以及处理额数据等。由Message列队,由Handler处理。
完成UI线程与工作线程建立消息循环,需要以下几个步骤:
(1) 生成工作线程的Looper,通过调用Looper.prepare()方法来实现。
(2) 将Handler与工作线程的Looper绑定,通过在工作线程中创建Handler对象实现。
(3) 定义消息处理方法,通过重写Handler的handlerMessage()方法实现。
(4) 启动消息循环,通过调用Looper.loop()方法实现。
(5) 结束消息循环,通过调用Looper.quit()方法实现。
是不是还不能满足你的胃口,上面这些一条一条如政治书上面的条目,实在让人提不起兴趣。下面将通过对Looper类和Handler类的解读来完成对Android消息处理机制的深入理解,看一下Google的大牛们是如何完成对Android消息循环的设计的。
首先来看下Looper的源码,Looper是消息的维护者,下面将会看到如何通过prepare()创建一个Looper,调用loop()执行消息循环,以及quit()推出消息循环。
public class Looper {
private static final String TAG = "Looper";
//sThreadLocal负责存放当前线程的唯一一个Looper
//ThreadLocal可以保证线程安全,关于ThreadLocal的深入理解,参照:
//
//如果没有调用prepare()方法,sThreadLocal.get()将会返回null
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//Looper里面的消息队列
final MessageQueue mQueue;
//当前线程
final Thread mThread;
//Looper是否开启,该变量使用volatile作为修饰,表示该变量是把修改过的值放到共享内存中,
//并且如果被线程访问又会从共享内存中重新读取该成员变量的值,这样保证多个线程总是访问到它的同一值
volatile boolean mRun;
//日志
private Printer mLogging = null;
//UI线程
private static Looper mMainLooper = null; // guarded by Looper.class
//prepare()用来初始化工作线程的Looper(后面还会看到loop()和quit()分别用来开始执行和结束一个loop)
//一个线程只能有一个Looper否则会抛出异常
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
//UI线程的Looper创建,该方法由Android系统提供。
//可以看到方法内部已经有了prepare()方法,所以在UI线程中我们看不到prepare()方法
public static void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
myLooper().mQueue.mQuitAllowed = false;
}
private synchronized static void setMainLooper(Looper looper) {
mMainLooper = looper;
}
/** Returns the application's main looper, which lives in the main thread of the application.
*/
public synchronized static Looper getMainLooper() {
return mMainLooper;
}
//消息循环
public static void loop() {
//获取当前Looper
Looper me = myLooper();
//当没有调用prepare()就直接调用loop()便会抛出异常
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//得到当前Looper的MessageQueue
MessageQueue queue = me.mQueue;
//确保当前线程属于当前进程,并记录下token。涉及到Android的权限检查,
//有兴趣的同学可以看下这篇文章:
//
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
//进入循环
while (true) {
//从消息队列中取出消息,有可能会阻塞
Message msg = queue.next(); // might block
if (msg != null) {
//target指的就是Handler,后面解析Handler源码的时候会有说明是为什么
if (msg.target == null) {
//当没有target也就是handler的时候,就退出消息
return;
}
long wallStart = 0;
long threadStart = 0;
//一个局部变量,为UI事件设置log记录
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
wallStart = SystemClock.currentTimeMicro();
threadStart = SystemClock.currentThreadTimeMicro();
}
//handler处理消息
msg.target.dispatchMessage(msg);
if (logging != null) {
long wallTime = SystemClock.currentTimeMicro() - wallStart;
long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
if (logging instanceof Profiler) {
((Profiler) logging).profile(msg, wallStart, wallTime,
threadStart, threadTime);
}
}
//确保分发消息的时候,线程没有被销毁
//涉及到Android的权限检查,有兴趣的同学可以看下这篇文章:
//
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
//回收Message
msg.recycle();
}
}
}
//返回线程相关Looper
public static Looper myLooper() {
return sThreadLocal.get();
}
//用来打印消息
public void setMessageLogging(Printer printer) {
mLogging = printer;
}
//返回和当前线程相关的MessageQueue,它必须是从一个有Looper的线程中被调用,
//否则,将会抛出空指针异常
public static MessageQueue myQueue() {
return myLooper().mQueue;
}
//创建一个新的looper对象
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
//退出消息循环
public void quit() {
Message msg = Message.obtain();
//往消息队列中加入一个空的msg,这就是为什么我们知道消息退出了
mQueue.enqueueMessage(msg, 0);
}
/**
* Return the Thread associated with this Looper.
*/
public Thread getThread() {
return mThread;
}
/** @hide */
public MessageQueue getQueue() {
return mQueue;
}
public void dump(Printer pw, String prefix) {
pw = PrefixPrinter.create(pw, prefix);
pw.println(this.toString());
pw.println("mRun=" + mRun);
pw.println("mThread=" + mThread);
pw.println("mQueue=" + ((mQueue != null) ? mQueue : "(null"));
if (mQueue != null) {
synchronized (mQueue) {
long now = SystemClock.uptimeMillis();
Message msg = mQueue.mMessages;
int n = 0;
while (msg != null) {
pw.println(" Message " + n + ": " + msg.toString(now));
n++;
msg = msg.next;
}
pw.println("(Total messages: " + n + ")");
}
}
}
public String toString() {
return "Looper{" + Integer.toHexString(System.identityHashCode(this)) + "}";
}
/**
* @hide
*/
public static interface Profiler {
void profile(Message message, long wallStart, long wallTime,
long threadStart, long threadTime);
}
}
下面来看下handler的源码,通过上面的消息循环的机制图我们可以看到handler主要负责消息的发送(sendMessage)以及消息的处理(handleMessage)
public class Handler {
private static final boolean FIND_POTENTIAL_LEAKS = false;
private static final String TAG = "Handler";
public interface Callback {
public boolean handleMessage(Message msg);
}
//该方法最终回调交给我们自己实现
public void handleMessage(Message msg) {
}
//在Looper中message的target就是handler,target调用dispatchMessage()处理消息
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//如果message设置了callback,处理callback
handleCallback(msg);
} else {
//如果handler本身设置了callback,执行callback
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//该方法需要我们覆写实现
handleMessage(msg);
}
}
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
//得到当前线程的Looper实例
mLooper = Looper.myLooper();
//如果当前线程没有Looper,这是会抛出异常,显示没有调用prepare()
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//关键来了!直接把Looper的Queue赋给自己的Queue,于是实现了handler与Looper的关联
mQueue = mLooper.mQueue;
mCallback = null;
}
....................
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//其它的发送消息的方法实际最后都是调用了该方法,下面解释了handler如何与Looper进行关联
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
//这就是为什么我们前面说msg.target就是指handler
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
....................
}
最后总结几点:
1. 在子线程中必须加Looper.prepare(), 用来创建对应的Looper。而在UI线程中,已经有了prepare(), 所以不需要加prepare().
2. 一个线程只能对应一个Looper,通过ThreadLocal存放为一个的一个Looper保证线程安全。
3. 一个Looper可以对应多个handler,直接把Looper的Queue赋给handler的Queue,实现它们之间的关联。
4. 一个Looper对应着一个MessageQueue,并由它来维护。
5. Handler中的handleMessage()回调方法,需要程序员进行覆写。