Android 基础 十一 Android的消息机制
一 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#1)mBooleanThreadLocal=false D/panzqww: (Thread#2)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 0; } 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(-1), mEpollRebuildRequired(false), mNextRequestSeq(0), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) { mWakeEventFd = eventfd(0, EFD_NONBLOCK); LOG_ALWAYS_FATAL_IF(mWakeEventFd < 0, "Could not make wake event fd. errno=%d", errno); AutoMutex _l(mLock); rebuildEpollLocked(); } Looper::~Looper() { close(mWakeEventFd); if (mEpollFd >= 0) { close(mEpollFd); } }
// Allocate the new epoll instance and register the wake pipe. mEpollFd = epoll_create(EPOLL_SIZE_HINT); LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
struct epoll_event eventItem; memset(& eventItem, 0, 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 != 0, "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(); ...... }
四、总结
4.1 底层流程