本次项目完成,对安卓的异步消息处理机制有了更深的了解,在这里总结一下。
Prolouge 先来回顾一下基础,Android中的异步消息处理主要由Message
, Handler
, MessageQueue
和Looper
四部分组成。
Message Message
主要作为线程之间传递的信息,它可以携带一些数据。它的what
字段(一般用来表示消息类型)、arg0
、arg1
字段可以携带一些整型数据,obj
字段可以携带一个对象,并且可以用setData
方法传输一个Bundle
对象。
Message
的创建方法有两种:
1
2
3
Message msg0 = new Message();
Message msg1 = Message.obtain();
Message message = mHandler.obtainMessage();
其中,Handler
的obtainMessage
方法也是调用了obtain
方法:
1
2
3
4
5
6
7
8
* Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
* creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
* If you don't want that facility, just call Message.obtain() instead.
*/
public final Message obtainMessage () {
return Message.obtain(this );
}
这两种方法的本质区别是,obtain
方法直接从消息池中获取Message
对象,这样很多时候可以避免创建新对象,减少内存开销,从obtain
方法的源码中就能看出这一点:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain () {
synchronized (sPoolSync) {
if (sPool != null ) {
Message m = sPool;
sPool = m.next;
m.next = null ;
m.flags = 0 ;
sPoolSize--;
return m;
}
}
return new Message();
}
因此,获取Message
时尽量使用obtain
方法。
Handler Handler
用于发送和处理信息,相当于生产者和消费者。Handler
通过sendMessage
方法将Message传入MessageQueue
消息队列,经Looper
轮询后将Message
传递至handleMessage
方法中。
最常见的一个应用就是需要在子线程中处理UI,这时候就需要借助Handler
实现。
MessageQueue MessageQueue
,顾名思义就是消息队列,它用来存放Handler
发送的消息,直到消息被处理。每个线程中只能有一个消息队列。
Looper Looper
相当于MessageQueue
的监视器。首先调用Looper.loop()
方法进入无限循环状态,每当一个新的Message
进入MessageQueue
,Looper
就会轮询,将此Message
传递给handleMessage
方法。每个线程中只能有一个Looper
对象。
底层实现 一个标准的异步处理流程应该是这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class LooperThread extends Thread {
public Handler mHandler;
public void run () {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage (Message msg) {
}
};
Looper.loop();
}
}
我们从Handler
的构造函数开始分析:
1
2
3
public Handler () {
this (null , false );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public Handler (Callback callback, boolean async) {
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());
}
}
mLooper = Looper.myLooper();
if (mLooper == null ) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()" );
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
如果我们直接在子线程中创建Handler
,会抛出异常,提示 “Can’t create handler inside thread that has not called Looper.prepare()”,也就是要调用Looper.prepare()
方法。根据源码,这是因为子线程的Looper为空所致,而观察prepare
方法的源码可知,此方法的作用就是创建一个Looper
对象:
1
2
3
4
5
6
7
8
9
10
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));
}
而主线程也没有调用Looper.prepare()
,为什么没有崩溃呢?显然是系统自动地帮我们调用了这个方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public static void main (String[] args) {
SamplingProfilerIntegration.start();
CloseGuard.setEnabled(false );
Environment.initForCurrentUser();
EventLogger.setReporter(new EventLoggingReporter());
Security.addProvider(new AndroidKeyStoreProvider());
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>" );
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false );
if (sMainThreadHandler == null ) {
sMainThreadHandler = thread.getHandler();
}
if (false ) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread" ));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited" );
}
其中的Looper.prepareMainLooper()
方法最后调用了Looper.prepare()
方法,创建了主线程的Looper。而子线程则不会主动创建Looper,必须自己调用方法创建。
创建完了Handler,下一步就是创建Message然后sendMessage
了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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 boolean sendMessageAtTime (Message msg, long uptimeMillis) {
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);
}
sendMessage
的结果是将此Message入队。注意到MessageQueue中只保存了当前待处理的一个对象,而不是一个集合;出队则是由Looper.loop()
进行:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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;
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next();
if (msg == null ) {
return ;
}
Printer logging = me.mLogging;
if (logging != null ) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null ) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
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);
}
msg.recycleUnchecked();
}
}
出队的逻辑为queue.next()
,其逻辑为:如果MessageQueue的待处理消息对象不为空,那么就出队并让下一个消息入队,否则阻塞。消息出队后经由dispatchMessage
方法回调,以便在handleMessage
中接收到Message并进行处理:
1
2
3
4
5
6
7
8
9
10
11
12
public void dispatchMessage (Message msg) {
if (msg.callback != null ) {
handleCallback(msg);
} else {
if (mCallback != null ) {
if (mCallback.handleMessage(msg)) {
return ;
}
}
handleMessage(msg);
}
}
这就是一个完整的异步消息处理机制,用网上的一幅图总结:
AsyncTask 当然从Android 1.5开始,谷歌就引入了一个更方便使用的AsyncTask
类用于处理异步任务,非常轻量级,通过实现其回调函数来实现相应逻辑。比如我写了一个异步读取缓存的Task:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private static class CacheTask extends AsyncTask <String , Void , User > {
private final WeakReference<Context> mContext;
private CacheTask (Context context) {
mContext = new WeakReference<>(context);
}
@Override
protected User doInBackground (String... params) {
Serializable object = XmlCacheManager.readObject(mContext.get(), "user" );
if (object == null ) {
return null ;
} else {
return (User) object;
}
}
@Override
protected void onPostExecute (User info) {
super .onPostExecute(info);
if (info != null ) {
mContext.get().mInfo = info;
mContext.get().mErrorLayout.setType(AppConstant.HIDE_ERROR_LAYOUT);
} else {
mContext.get().mErrorLayout.setType(AppConstant.NETWORK_ERROR_LAYOUT);
}
mContext.get().updateUI();
}
}
在此逻辑中,doInBackground
方法用于执行具体的缓存读取,而onPostExecute
方法用于通知UI更新任务的结果(即更新UI)。其实AsyncTask底层也是利用上边的异步消息机制实现的,只不过它封装地非常好,免去了开发者自己写Message和Handler的环节,减少编码量。
粗略看了一下AsyncTask的源码,发现其的底层实现用了各种JUC的东西,以后有时间再研究研究它的源码。