一 Handler使用
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
针对checkThread方法中抛出的异常信息,相信大家在开发中都曾经遇到过。由于这一点的限制,导致必须在主线程中访问UI,但是Android又建议不要在主线程中进行耗时操作,否则会导致程序无法响应即ANR。考虑一种情况,假如我们需要从服务端拉取一些信息并将其显示在UI上,这个时候必须在子线程中进行拉取工作,拉取完毕后又不能在子线程中直接访问UI,如果没有Handler,那么我们的确没办法将访问UI的工作切换到主线程中去执行。因此系统之所以提供Handler,主要原因是为了解决在子线程中无法访问UI的矛盾。
1.1 Handler的使用方法
1.1.1 常见方法
sendEmptyMessage:
mHandler.sendEmptyMessage(1001);
mHandler.sendEmptyMessageAtTime(1002,SystemClock.uptimeMillis()+1000);
mHandler.sendEmptyMessageDelayed(1003,3000);
取消:mHandler.removeMessages(1003);
sendMessage:
Message message2 = Message.obtain();
mHandler.sendMessage(message1);
mHandler.sendMessageAtTime(message2,SystemClock.uptimeMillis()+1000);
mHandler.sendMessageDelayed(message3,3000);
取消:mHandler.removeMessages(1003);
post:
mHandler.post(runnable);
mHandler.postDelayed(runnable,3000);
取消:mHandler.removeCallbacks(runnable);
sendToTarget
Message message = mHandler.obtainMessage();
message.sendToTarget();
public void sendToTarget() {
target.sendMessage(this);
}
在Message的官方文档中,有这样一句话:
1.1.2 sendMessage源码分析
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) {
//异常处理
}
return enqueueMessage(queue, msg, uptimeMillis);
}
...
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
上面enqueueMessage()方法首先设置了这个消息的目标处理对象target,即这个消息最终由谁来处理,这里赋值为this,表示这个消息最终由目前发送的Handle来处理,接着enqueueMessage方法调用MessageQueue中enqueueMessage方法来把这个消息加入到应用程序的消息队列中去,queue是一个MessageQueue对象
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
} msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
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
// 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.next = p; // invariant: p == prev.next
prev.next = msg;
} // We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
Handler发送消息最终都会调用到sendMessageAtTime方法,在这个方法里面就做了一件事,将消息放入一个消息队列中。如果新消息首次加入队列,或者新消息延迟时间要小于队列首个消息延迟时间,就将新消息放在队列首部。如果队列不为空,新消息延迟时间并不是最短,就将新消息插入到队列的某个位置。
1.2 Handler简单实例
public class HandlerActivity extends Activity implements View.OnClickListener {
private Button btn_main_to_sub;
private Button btn_sub_to_main;
Handler mMainHandler;
Handler mSubHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
mMainHandler = new MainHandler();
new MainToSubThread().start();
initViews();
}
private void initViews() {
btn_main_to_sub = findViewById(R.id.main_to_sub);
btn_sub_to_main = findViewById(R.id.sub_to_main);
btn_sub_to_main.setOnClickListener(this);
btn_main_to_sub.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.main_to_sub:
Log.d("panzqww", "onClick --- MainThread to SubThread");
Message msg = mSubHandler.obtainMessage();
msg.obj = "从主线发送给子线程的消息 555";
mSubHandler.sendMessage(msg);
break;
case R.id.sub_to_main:
Log.d("panzqww", "onClick --- SubThread to MainThread");
new SubToMainThread().start();
break;
}
}
class MainHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String msg_obj = (String) msg.obj;
longRunningMethod();//主线程运行耗时操作会出现ANR异常
Log.d("panzqww", "我是主线程 ,接收到子线程的消息: " + msg_obj);
}
}
class SubToMainThread extends Thread {
@Override
public void run() {
super.run();
Message msg = mMainHandler.obtainMessage();
msg.obj = "从子线发送给主线程的消息 666";
mMainHandler.sendMessage(msg);
}
}
class MainToSubThread extends Thread {
@Override
public void run() {
super.run();
Looper.prepare();
mSubHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String msg_obj = (String) msg.obj;
Log.d("panzqww", "我是子线程,接收到主线程的消息:" + msg_obj);
longRunningMethod();//子线程执行耗时操作不会出现ANR异常
}
};
Looper.loop();
}
}
private void longRunningMethod() {
long i = 0;
long sum = 0;
while (i < 10000) {
sum += i;
SystemClock.sleep(1);
i++;
}
Log.d("panzqww", " 耗时操作结果 sum = " + sum);
}
}
上述代码想要阐述的是:
- 1.如何在Thread中定义一个Handler
- 2.在Thread定义的Handler跟在主线程中的Handler有什么区别
二、Android的消息机制分析
- Message:Message是在线程之间传递的消息,它可以在内部携带少量的数据,用于线程之间交换数据。Message有四个常用的字段,what字段,arg1字段,arg2字段,obj字段。what,arg1,arg2可以携带整型数据,obj可以携带object对象。
- Handler:它主要用于发送和处理消息,发送消息一般使用sendMessage()方法,还有其他的一系列sendXXX的方法,但最终都是调用了sendMessageAtTime方法。而发出的消息经过一系列的辗转处理后,最终会传递到Handler的handleMessage方法中。
- MessageQueue:MessageQueue是消息队列的意思,它主要用于存放所有通过Handler发送的消息,这部分的消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue对象。
- Looper:每个线程通过Handler发送的消息都保存在MessageQueue中,Looper通过调用loop()的方法,就会进入到一个无限循环当中,然后每当发现MessageQueue中存在一条消息,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中只会有一个Looper对象。
- ThreadLocal:MessageQueue对象和Looper对象在每个线程中都只会有一个对象,怎么能保证它这个对象,就通过ThreadLocal来保存。ThreadLocal是一个线程内部的数据存储类,通过它可以在指定线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储到数据,对于其他线程来说则无法获取到数据。
2.1 ThreadLocal的工作原理
2.1.1 ThreadLocal单独介绍
/**
* Implements a thread-local storage, that is, a variable for which each thread
* has its own value. All threads share the same {@code ThreadLocal} object,
* but each sees a different value when accessing it, and changes made by one
* thread do not affect the other threads. The implementation supports
* {@code null} values.
*
* @see java.lang.Thread
* @author Bob Lee
*/
以上是源码(libcore/luni/src/main/java/java/lang/ThreadLocal.java)中对ThreadLocal的解释,意思是“实现线程本地存储,即每个线程都有自己的值。所有线程都共享同一个{@code ThreadLocal}对象,但是在访问时,每个线程都看到不同的值,一个线程所做的更改不会影响其他线程。该实现支持{@code null}值”。从这里我们可以看出,ThreadLocal相当于一个容器,存储着每个线程的数据,且所有线程都共享这一个ThreadLocal变量,但每个线程访问该对象时竟然会获得的数据都不同,而且就算修改这些数据也不会影响到其他线程,即所有线程互不干扰。因为这个特性,ThreadLocal在Java中也常用于处理多线程,也就是说,ThreadLocal和线程同步机制一样,都是为了解决多线程访问同一变量造成的访问冲突问题,不同的的是:同步机制是通过锁机制牺牲时间来达到多线程安全访问的目的;ThreadLocal为每个线程提供独立的变量副本,牺牲空间保证每个线程访问相同变量时可以得到自己专属的变量,达到多线程安全访问的目的。
private ThreadLocal<Boolean> mBooleanThreadLocal = new ThreadLocal<Boolean>();
mBooleanThreadLocal.set(true);
Log.d(TAG, "Thread#main mBooleanThreadLocal=" + mBooleanThreadLocal.get());
new Thread("Thread#1"){
@Override
public void run() {
mBooleanThreadLocal.set(false);
Log.d(TAG, "Thread#1 mBooleanThreadLocal=" + mBooleanThreadLocal.get());
}
}.start(); new Thread("Thread#2"){
@Override
public void run() {
Log.d(TAG, "Thread#2 mBooleanThreadLocal=" + mBooleanThreadLocal.get());
}
}.start();
D/panzqww: (Thread#main)mBooleanThreadLocal=true
D/panzqww: (Thread#)mBooleanThreadLocal=false
D/panzqww: (Thread#)mBooleanThreadLocal=null
2.1.2 ThreadLocal内部实现
/** Size must always be a power of 2. */
private static final int INITIAL_SIZE = 16;
/** Placeholder for deleted entries. */
private static final Object TOMBSTONE = new Object();
/**
* Map entries. Contains alternating keys (ThreadLocal) and values.
* The length is always a power of 2.
*/
private Object[] table;
/** Used to turn hashes into indices. */
private int mask;
/** Number of live entries. */
private int size; /** Number of tombstones. */
private int tombstones; /** Maximum number of live entries and tombstones. */
private int maximumLoad; /** Points to the next cell to clean up. */
private int clean; Values() {
initializeTable(INITIAL_SIZE);
this.size = 0;
this.tombstones = 0;
} private void initializeTable(int capacity) {
this.table = new Object[capacity * 2];
this.mask = table.length - 1;
this.clean = 0;
this.maximumLoad = capacity * 2 / 3; // 2/3
}
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 void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
} Values values(Thread current) {
return current.localValues;
} Values initializeValues(Thread current) {
return current.localValues = new Values();
}
void put(ThreadLocal<?> key, Object value) {
// Cleans up after garbage-collected thread locals.
cleanUp();
// Keep track of first tombstone. That's where we want to go back
// and add an entry if necessary.
int firstTombstone = -1;
for (int index = key.hash & mask;; index = next(index)) {
Object k = table[index];
if (k == key.reference) {
// Replace existing entry.
table[index + 1] = value;
return;
}
if (k == null) {
if (firstTombstone == -1) {
// Fill in null slot.
table[index] = key.reference;
table[index + 1] = value;
size++;
return;
}
// Go back and replace first tombstone.
table[firstTombstone] = key.reference;
table[firstTombstone + 1] = value;
tombstones--;
size++;
return;
}
// Remember first tombstone.
if (firstTombstone == -1 && k == TOMBSTONE) {
firstTombstone = index;
}
}
}
private int next(int index) {
return (index + 2) & mask;
}
public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this);
}
Values values(Thread current) {
return current.localValues;
}
Values initializeValues(Thread current) {
return current.localValues = new Values();
}
可以看到,这里依然是通过当前线程自身的localValues这个值内部的table数组来获得相关联的looper对象,如果是null,则重新初始化该Values对象,如果不为null则返回table数组中该ThreadLocal对象的引用所在位置的下一个值,也就是我们前面set进去looper。
2.2 MessageQueue的工作原理
2.2.1 消息队列读取
public class MessageQueue { ...... private int mPtr; // used by native code private native static long nativeInit(); MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
} ...... }
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
} msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
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
// 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.next = p; // invariant: p == prev.next
prev.next = msg;
} // We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->wake();
}
void NativeMessageQueue::wake() {
mLooper->wake();
}
void Looper::wake() {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ wake", this);
#endif
uint64_t inc = 1;
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
if (nWrite != sizeof(uint64_t)) {
if (errno != EAGAIN) {
ALOGW("Could not write wake signal, errno=%d", errno);
}
}
}
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, 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;
if (msg != null) {
if (now < msg.when) {
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// 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 = 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(TAG, "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;
}
}
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
jlong ptr, jint timeoutMillis) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}
void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
mPollEnv = env;
mPollObj = pollObj;
mLooper->pollOnce(timeoutMillis);
mPollObj = NULL;
mPollEnv = NULL; if (mExceptionObj) {
env->Throw(mExceptionObj);
env->DeleteLocalRef(mExceptionObj);
mExceptionObj = NULL;
}
}
2.2.2 消息队列底层实现
NativeMessageQueue::NativeMessageQueue() :
mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = new Looper(false);
Looper::setForThread(mLooper);
}
}
...
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
if (!nativeMessageQueue) {
jniThrowRuntimeException(env, "Unable to allocate native queue");
return ;
}
nativeMessageQueue->incStrong(env);
return reinterpret_cast<jlong>(nativeMessageQueue);
}
sp<MessageQueue> android_os_MessageQueue_getMessageQueue(JNIEnv* env, jobject messageQueueObj) {
jlong ptr = env->GetLongField(messageQueueObj, gMessageQueueClassInfo.mPtr);
return reinterpret_cast<NativeMessageQueue*>(ptr);
}
2.3 Looper的工作原理
2.3.1 Looper上层实现
public class Looper {
......
private static final ThreadLocal sThreadLocal = new ThreadLocal();
final MessageQueue mQueue;
......
/** 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 final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
/** Initialize the current thread as a looper, marking it as an application's main
* looper. The main looper for your application is created by the Android environment,
* so you should never need to call this function yourself.
* {@link #prepare()}
*/
public static final void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
if (Process.supportsProcesses()) {
myLooper().mQueue.mQuitAllowed = false;
}
}
private synchronized static void setMainLooper(Looper looper) {
mMainLooper = looper;
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
......
}
new Thread("Thread#2"){
@Override
public void run() {
Looper.prepare();
Handler handler = new Handler();
Looper.loop();
}
}.start();
Looper除了prepare方法外,还提供了prepareMainLooper方法,这个方法主要时给主线程也就是ActivityThread创建Looper使用的,其本质也是通过prepare方法来实现的。由于主线程的Looper比较特殊,所以Looper提供了一个getMainLooper方法,即通过getMainLooper方法可以在任何地方获取到主线程的Looper。Looper也是可以退出的,Looper提供了quit和quitSafely来退出一个Looper,二者的区别是:quit会直接退出Looper,而quitSafely只是设定一个退出标记,然后把消息队列中的已有消息处理完毕后才安全地退出。Looper退出后,通过Handler发送的消息会失败,这个时候Handler的send方法会返回false。在子线程中如果手动为其创建了Looper,那么在所有的事情完成以后应该调用quit方法来终止循环,否则这个子线程就会一直处于等待的状态,而如果退出了Looper以后,这个线程就会立刻终止,因此建议不需要的时候终止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;
// 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);
}
msg.target.dispatchMessage(msg);
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的loop方法的工作过程比较好理解,loop方法是一个死循环,唯一跳出循环的方式是MessageQueue的next方法返回了null。当Looper的quit方法被调用时,Looper就会调用MessageQueue的quit或者quitSafely方法来通知消息队列退出,当消息队列被标记为退出状态时,它的next方法就会返回null。也就是说Looper必须退出,否则Loop方法就会无限循环下去。loop方法会调用MessageQueue的next方法来获取新消息,而next时一个阻塞操作,当没有消息时,next方法会一直阻塞在那里,这也导致loop方法一直阻塞在哪里。如果MessageQueue的next方法返回了新消息,Looper就会处理这条消息:msg.target.dispatchMessage(msg),这里的msg.target发送这条消息的Handler对象,这样Handler发送的消息最终又交给它的dispatchMessage方法来处理了。但是这里不同的是,Handler的dispatchMessage方法是在创建Handler时所使用的Looper中执行的,这样就成功地将代码逻辑切换到指定地线程中去执行了。
2.3.2 Looper底层实现
Looper::Looper(bool allowNonCallbacks) :
mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
mPolling(false), mEpollFd(-), mEpollRebuildRequired(false),
mNextRequestSeq(), mResponseIndex(), mNextMessageUptime(LLONG_MAX) {
mWakeEventFd = eventfd(, EFD_NONBLOCK);
LOG_ALWAYS_FATAL_IF(mWakeEventFd < , "Could not make wake event fd. errno=%d", errno); AutoMutex _l(mLock);
rebuildEpollLocked();
} Looper::~Looper() {
close(mWakeEventFd);
if (mEpollFd >= ) {
close(mEpollFd);
}
}
// Allocate the new epoll instance and register the wake pipe.
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
LOG_ALWAYS_FATAL_IF(mEpollFd < , "Could not create epoll instance. errno=%d", errno);
struct epoll_event eventItem;
memset(& eventItem, , sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeEventFd;
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, & eventItem);
LOG_ALWAYS_FATAL_IF(result != , "Could not add wake event fd to epoll instance. errno=%d",
errno);
2.4 Handler的工作原理
public class Handler {
......
public Handler() {
......
mLooper = Looper.myLooper();
......
mQueue = mLooper.mQueue;
......
} final MessageQueue mQueue;
final Looper mLooper;
......
}
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);
} private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
/**
Callback interface you can use when instantiating a Handler to avoid having
to implement your own subclass of Handler.
@param msg A{@link android.os.Message Message} object
@return True if no further hadling is desired
*/
public interface Callback {
public boolean handleMessage(Message msg);
}
public Handler(Looper looper) {
this(looper, null, false);
}
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;
}
三、主线程的消息循环
public final class ActivityThread {
......
public static final void main(String[] args) {
.....
Looper.prepareMainLooper();
......
ActivityThread thread = new ActivityThread();
thread.attach(false);
......
Looper.loop();
......
thread.detach();
......
}
}
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100;
public static final int PAUSE_ACTIVITY = 101;
public static final int PAUSE_ACTIVITY_FINISHING= 102;
public static final int STOP_ACTIVITY_SHOW = 103;
public static final int STOP_ACTIVITY_HIDE = 104;
public static final int SHOW_WINDOW = 105;
public static final int HIDE_WINDOW = 106;
public static final int RESUME_ACTIVITY = 107;
public static final int SEND_RESULT = 108;
public static final int DESTROY_ACTIVITY = 109;
public static final int BIND_APPLICATION = 110;
public static final int EXIT_APPLICATION = 111;
public static final int NEW_INTENT = 112;
public static final int RECEIVER = 113;
public static final int CREATE_SERVICE = 114;
public static final int SERVICE_ARGS = 115;
public static final int STOP_SERVICE = 116;
...
}
public final class ActivityThread {
......
private final class ApplicationThread extends ApplicationThreadNative {
......
// we use token to identify this activity without having to send the
// activity itself back to the activity manager. (matters more with ipc)
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) {
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.activityInfo = info;
r.state = state;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
}
......
}
......
}
public final class ActivityThread {
......
private final class ApplicationThread extends ApplicationThreadNative {
......
// if the thread hasn't started yet, we don't have the handler, so just
// save the messages until we're ready.
private final void queueOrSendMessage(int what, Object obj) {
queueOrSendMessage(what, obj, 0, 0);
}
......
private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
synchronized (this) {
......
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
mH.sendMessage(msg);
}
}
......
}
......
}
public final class ActivityThread {
......
private final class H extends Handler {
......
public void handleMessage(Message msg) {
......
switch (msg.what) {
......
}
......
}
......
}
public final class ActivityThread {
......
public static final void main(String[] args) {
......
ActivityThread thread = new ActivityThread();
thread.attach(false);
......
}
}
public final class ActivityThread {
......
final H mH = new H();
......
}