Android开发中经常使用Handler来实现“跨越线程(Activity)更新UI”。本文将从源码角度回答:为什么使用Handler能够跨线程更新UI?为什么跨线程更新UI一定要用Handler?
Demo
Demo1. 用Handler更新UI
下面这个Demo完全是为了演示“跨线程更新UI”而写的。界面上只有一个TextView和一个Button,按下Button创建一个后台线程,该后台线程每隔一秒更新一次TextView,连续更新10次,结束。
Activity的代码如下:
public class MainActivity extends Activity {
static final String TAG = "MainActivity";
Handler handler = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView text = (TextView)findViewById(R.id.txtHello);
Button button = (Button)findViewById(R.id.btnRun);
button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
Log.d(TAG, "clicked!");
new Thread() {
public void run() {
for(int i=0; i<10; i++) {
Message msg = new Message();
msg.what = 1;
msg.obj = "item-"+i;
handler.sendMessage(msg);
Log.d(TAG, "sended "+"item-"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
});
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
String str = "unknow";
switch(msg.what) {
case 1:
str = (String)msg.obj;
break;
default:
break;
}
Log.d(TAG, "recv " + str);
text.setText(str);
super.handleMessage(msg);
}
};
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
布局文件较为简单:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/txtHello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<Button
android:id="@+id/btnStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start"
/>
</RelativeLayout>
这里展示的是Handler的典型用法――用来更新UI控件。
下面再展示一个非典型用法,仅仅是为了后面的分析方便。
Demo2. 自制ActivityThread模拟Activity
本例是为了分析方便而创建的;使用一个线程LooperThread来模拟Activity。
后面阐述为什么要这么做,代码如下:
package com.example.handlerdemo;
import android.os.Bundle;
import android.os.Message;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
static final String TAG = "MainActivity";
ActivityThread acitivityThread = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupViews();
}
private void setupViews() {
TextView tv = (TextView)findViewById(R.id.txtHello);
Button bt = (Button)findViewById(R.id.btnStart);
Log.d(TAG, String.format("[MainActivity] Thread %s(%d)",
Thread.currentThread().getName(), Thread.currentThread().getId()));
acitivityThread = new ActivityThread();
acitivityThread.start();
acitivityThread.waitForHandlerReady();
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
for(int i=0; i<10; i++) {
Message msg = new Message();
msg.what = i;
acitivityThread.mHandler.sendMessage(msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
MainActivity.java
package com.example.handlerdemo;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
public class ActivityThread extends Thread {
static final String TAG = "LooperThread";
public Handler mHandler = null;
public ActivityThread() {
super("LooperThread");
}
@Override
public void run() {
Looper.prepare();
synchronized(this) {
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.d(TAG, String.format("recv msg.what: %d in Thread: %s(%d)", msg.what,
Thread.currentThread().getName(),Thread.currentThread().getId()));
}
};
this.notify();
}
Looper.loop();
}
public void waitForHandlerReady() {
try {
synchronized(this) {
while(mHandler == null)
this.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ActivityThread.java
这个Demo的布局文件很简单,就不贴出来了。
为什么使用Handler能够跨线程更新UI?
概览
以Demo2为例,这个Demo至少涉及三个线程:GodActivity线程,ActivityThread线程(模拟UI),匿名线程(GodActivity创建的,叫他aThread)。暂且把GodActivity当做上帝,把ActivityThread看做Demo1里的Activity。现在,我们先预览一下为什么aThread可以通过Handler来更新ActivityThread的UI(纯属虚构),这两个线程的交互关系如下图所示:
(PS:此前的版本画了很多对象的生命线,结果很混乱,删了一堆无关紧要的之后,立刻清晰了,^_^)
这个序列图(Sequence Diagram)已经简洁明了地给出了答案:
- Activity线程的幕后还有一个MessageQueue;MessageQueue故名思议是一个Message组成的Queue;
- aThread只是将数据以Message的形式挂到了Activity幕后的MessageQueue上了;
- Activity线程从MessageQueue上取Message并调用Handler.handlerMessage,所以实际的“更新动作”还是发生在Activity线程内;
详解
下面将从Android 4.4.4源码的角度分析Handler的“幕后黑手”。
几个关键类
Demo2中和Handler有关的类除了MessageQueue还有Message和Looper,这几个类的关系如下:
关键点:
- MessageQueue通过Message.next维护链表结构(java引用即指针);
- ActivityThread的消息循环被封装在Looper.loop()内,Looper.prepare()用于创建属于当前线程的Looper和MessageQueue;
- 每个Message可以通过target指向一个Handler,Handler实际上就是一个用来处理Message的callback;
接下来的代码,只贴代码片段(方法),如果对各类的属性有所疑惑,可以回头查看此图。
Looper.prepare()
根据Looper的注释可以看到,Looper线程“三部曲”:
- Looper.prepare()
- new Handler() { /* override handleMessage() */ }
- Looper.loop();
下面逐渐切入Looper.prepare():
public static void prepare() {
prepare(true);
}
Looper.java
无参数版本调用了有参数版本:
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.java
这段代码中引用了sThreadLocal,它被定义为ThreadLocal类型,即线程私有数据类型(或者叫做线程级别单例)
ThreadLocal<T>可以理解为Map<Thread,T>的一层包包装(实际上Android,JVM都是按Map实现的,感兴趣的同学可自行研究;set(value)时,以当前线程对象为key,所以每个线程能够保存一份value。)
可见Looper.prepare()调用使得AcitivityThread通过Looper.sThreadLocal<Looper>持有了一个Looper对象。
继续看Looper的构造方法Looper(quitAllowed):
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread(); // 和当前线程关联
}
Handler.java
可以看到Looper的构造函数中创建了一个MessageQueue。
流程又转到了MessageQueue的构造函数MessageQueue(quitAllowed):
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
MessageQueue.java
Handler()
首先看上面调用的默认构造方法:
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread. 将当前线程的Looper与此handler关联。
* 如果当前线程没有looper,这个handler将不能接收消息,从而导致异常抛出
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler() {
this(null, false);
}
Handler.java
默认构造方法又调用了另一版本的构造方法,如下:
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) { // FIND_POTENTIAL_LEAKS 为 false;
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(); // 获取当前线程(调用者)的Looper
if (mLooper == null) { // 如果当前线程没有Looper,则抛异常
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; // 这里引用的MessageQueue是Looper()中创建的
mCallback = callback;
mAsynchronous = async;
}
Handler.java
Handler()调用了Looper.myLooper():
public static Looper myLooper() {
return sThreadLocal.get(); // 从该线程的“单例”中取出Looper对象
}
Looper.java
Looper.loop()
Looper.loop()封装了消息循环,所以我们现在看看Looper.loop()的“真面目”:
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;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block, 取出消息
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
// mLatencyLock is only initialized for non USER builds
// (e.g., USERDEBUG and ENG)
if ((!sLatencyEnabled) || (me != sMainLooper)) {
msg.target.dispatchMessage(msg); // 通过msg.target分派消息
}
else { // 记录性能数据
long t1 = SystemClock.uptimeMillis(); // 获得当前毫秒数(自启动)
msg.target.dispatchMessage(msg);
long t2 = SystemClock.uptimeMillis() - t1; // t2就是dispatchMessage(msg)所用时间
if (t2 < 50) {
// We don't care about these from a latency perspective
}
else if (t2 < 250) {
// Fast response that usually has low impact on user experience
sLatencyCountFast++;
sLatencySumFast += t2;
if (sLatencyCountFast >= 100) {
String name = getProcessName();
long avg = sLatencySumFast / sLatencyCountFast;
EventLog.writeEvent(2731, "mainloop2_latency1", name, avg);
sLatencyCountFast = 0;
sLatencySumFast = 0;
}
}
else if (t2 < 1000) {
sLatencyCountSlow++;
sLatencySumSlow += t2;
if (sLatencyCountSlow >= 10) {
String name = getProcessName();
long avg = sLatencySumSlow / sLatencyCountSlow;
EventLog.writeEvent(2731, "mainloop2_latency2", name, avg);
sLatencyCountSlow = 0;
sLatencySumSlow = 0;
}
}
else {
String name = getProcessName();
EventLog.writeEvent(2731, "mainloop2_bad", name, t2);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
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.recycle();
}
}
Looper.java
可以看到,Looper.loop()的for循环实际上就是“消息循环”,它负责从消息队列(MessageQueue)中不断地取出消息(MessageQueue.next),然后通过msg.target来派发(dispatch)消息。
How to dispatch?
下面看看Message到底是如何被dispatch的:
public void dispatchMessage(Message msg) {
if (msg.callback != null) { // 方法 1
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) { // 方法 2
return;
}
}
handleMessage(msg); // 方法 3
}
}
Handler.java
从这段代码可以看出,实现正常的Message处理有三种方式:
- 为Message.callback注册一个Runnable实例。
- 为Handler.mCallback注册一个Handler.Callback实例。
- 重写Handler的handleMessage方法。
另外,这三种方法优先级依次降低,且一个Message只能有一种处理方式。
Message的发送与获取
对于一个后台线程,它要发出消息(Handler.sendMessage);对于Activity线程,它要得到其他线程发来的消息(MessageQueue.next);而这两种工作都是以MessageQueue为基础的。下面,分别分析发送和接收的具体流程:
Handler.sendMessage()
Demo中后台线程正是通过Handler.sendMessage实现向Activity发消息的,Handler.sendMessage方法的代码如下:
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
Handler.java
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
Handler.java
其中,其中SystemClock.uptimeMillis()返回自启动以来CPU经过的毫秒数。
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);
}
Handler.java
Handler.enqueMessage其实只是对MessageQueue.enqueueMessage的简单包装:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; // 将当前Handler(通常已重写handleMessage方法)与该Message绑定(通过target)
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis); // 调用MessageQueue.enqueueMessage
}
Handler.java
这里看到了Looper.loop()里引用的target的来源。
流程转到了MessageQueue.enqueueMessage(),看命名基本知道它是入队操作,代码如下:
boolean enqueueMessage(Message msg, long when) {
if (msg.isInUse()) {
throw new AndroidRuntimeException(msg + " This message is already in use.");
}
if (msg.target == null) {
throw new AndroidRuntimeException("Message must have a target.");
}
synchronized (this) { // 临界区
if (mQuitting) {
RuntimeException e = new RuntimeException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
}
msg.when = when;
Message p = mMessages; // 链表头
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// p == null 队列为空
// when == 0 由 Handler.sendMessageAtFrontOfQueue() 发出
// when < p.when 新消息的when比队头要早
// New head, wake up the event queue if blocked.
msg.next = p; // 将msg放到队头,step 1
mMessages = msg; // 将msg放到队头,step 2
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake 插到队列中间。通常我们不必唤醒
// up the event queue unless there is a barrier at the head of the queue 事件(event)队列,除非队头有一个barrier,
// and the message is the earliest asynchronous message in the queue.且消息是队列中最早的同步消息。
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) { // 遍历链表
prev = p;
p = p.next;
if (p == null || when < p.when) { // 到“尾部”了 或 新消息比当前消息更早
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
// 以下两行将msg插入prev和p之间
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr); // 通知前台线程“有消息来啦”
}
}
return true;
}
MessageQueue.java
根据这段代码可知,MessageQueue上的Message是按照when大小排列的。唯一可能让人疑惑的是最后的nativeWake,稍后讨论。
MessageQueue.next()
前文的Looper.loop方法通过MessageQueue.next()取出消息,现在看看它是如何实现的:
Message next() {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// We can assume mPtr != 0 because the loop is obviously still running.
// The looper will not call this method after the loop quits.
nativePollOnce(mPtr, nextPollTimeoutMillis); // 等待通知,可能阻塞
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages; // 链表头
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do { // 遍历链表
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next; // 将msg节点摘下
} else { // prevMsg == null, msg是链表头
mMessages = msg.next;
}
msg.next = null; // msg与MessageQueue“断绝关系”
if (false) Log.v("MessageQueue", "Returning message: " + msg);
msg.markInUse();
return msg; // 退出点1 到这为止,是常规逻辑
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null; // 退出点2
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("MessageQueue", "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
MessageQueue.java
MessageQueue.next()同样让人疑惑的是nativePollOnce,稍后也将见分晓。
小结
MessageQueue.next()和MessageQueue.sendMessage()分别被Activity线程、后台线程调用,而他们两个线程可能同时在调用这两个方法,所以他们共享并修改的成员变量需要加锁,这就是synchronized (this)出现的原因。
至此,已经能够完整的回答“为什么用Handler能够实现跨线程更新UI”。简单的说,Activity线程的背后都有一个消息队列(MessageQueue),后台线程通过Handler的sendMessage方法向这个消息队列上放消息;Activity线程将消息从消息队列上取下来之后,通过具体Handler的handleMessage方法处理消息,而更新UI的代码就在这个handleMessage中;所以,后台线程并没有做实际的“更新”,只是将要更新的内容以借助MessageQueue告诉了Activity线程,Activity线程才是实际做“更新”动作的人。
简言之,Handler并没有真正的实现“跨线程”更新UI,而是将要更新的数据(Message携带)和如何更新(Handler携带)通过消息队列告诉了UI线程,UI线程才是真正的“幕后英雄”。
真正的ActivityThread
Demo2中的ActivityThread完全是虚构出来的,下面来看看Android的Activity到底是不是想我虚构的那样有一个Looper。
经过上面的分析,可以从两方面验证:
- 看看Activity源码中执行onCreate之前是否调用了Looper.prepare()。
- 执行onXXX方法时的CallStack上是否有Looper.loop();
第二点很容易验证,只需在任意onXXX方法中打一个断点,然后看程序的CallStack,就一面了然了:
根据这个调用栈,可以很明显的看到有Looper.loop;同时还能看到是ActivityThread.main调用它的,所以可以看看ActivityThread.main的源码:
public static void main(String[] args) {
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
Security.addProvider(new AndroidKeyStoreProvider());
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper(); // 它和Looper.prepare类似
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
ActivityThread.java
所以,上面提到的两方面都得到了验证。即真正的ActivityThread是有Looper的。
Native浮云
细心的朋友可能会发现,上面MessageQueue的代码中还遗留几个native开头方法:nativeInit,nativePollOnce,nativeWake。
下面就来扫清这些“遮眼”的浮云。和这几个native方法直接对应的是:
static JNINativeMethod gMessageQueueMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit", "()I", (void*)android_os_MessageQueue_nativeInit },
{ "nativeDestroy", "(I)V", (void*)android_os_MessageQueue_nativeDestroy },
{ "nativePollOnce", "(II)V", (void*)android_os_MessageQueue_nativePollOnce },
{ "nativeWake", "(I)V", (void*)android_os_MessageQueue_nativeWake },
{ "nativeIsIdling", "(I)Z", (void*)android_os_MessageQueue_nativeIsIdling }
};
android_os_MessageQueue.cpp
nativeInit
下面从adnroid_os_MessageQueue_nativeInit开始,顾名思义,nativeInit当然是完成一些初始化工作的。
static jint android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue(); // 创建了NativeMessageQueue
if (!nativeMessageQueue) {
jniThrowRuntimeException(env, "Unable to allocate native queue");
return 0;
}
nativeMessageQueue->incStrong(env);
return reinterpret_cast<jint>(nativeMessageQueue);
}
android_os_MessageQueue.cpp
看看NativeMessageQueue的声明:
class NativeMessageQueue : public MessageQueue {
public:
NativeMessageQueue();
virtual ~NativeMessageQueue();
virtual void raiseException(JNIEnv* env, const char* msg, jthrowable exceptionObj);
void pollOnce(JNIEnv* env, int timeoutMillis);
void wake();
private:
bool mInCallback;
jthrowable mExceptionObj;
};
android_os_MessageQueue.cpp
NativeMessageQueue继承了MessageQueue,再来看看MessageQueue的声明:
class MessageQueue : public RefBase {
public:
/* Gets the message queue's looper. */
inline sp<Looper> getLooper() const {
return mLooper;
}
/* Checks whether the JNI environment has a pending exception.
*
* If an exception occurred, logs it together with the specified message,
* and calls raiseException() to ensure the exception will be raised when
* the callback returns, clears the pending exception from the environment,
* then returns true.
*
* If no exception occurred, returns false.
*/
bool raiseAn
------分隔线----------------------------
------分隔线----------------------------