第一次接觸Android應用程序(這裡指的是JAVA層的UI程序,也難怪了,Google放出的API就只支持JAVA應用程序了),很難搞明白內部是如何實現的。但是,從原理上分析,應該是有一個消息循環,一個消息隊列,然後主線程不斷得從消息隊列中取得消息並處理之。
然而,google封裝得太厲害了,所以一時半會還是搞不清楚到底是怎麼做的。本文將分析android內的looper,這個是用來封裝消息循環和消息隊列的一個類,handler其實可以看做是一個工具類,用來向消息隊列中插入消息的。好比是Windows API的SendMessage中的HANDLE,這個handle是窗口句柄。
- //Looper類分析
- //沒找到合適的分析代碼的辦法,只能這麼來了。每個重要行的上面都會加上注釋
- //功能方面的代碼會在代碼前加上一段分析
- public class Looper {
- //static變量,判斷是否打印調試信息。
- private static final boolean DEBUG = false;
- private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
-
- // sThreadLocal.get() will return null unless you've called prepare().
- //線程本地存儲功能的封裝,TLS,thread local storage,什麼意思呢?因為存儲要麼在棧上,例如函數內定義的內部變量。要麼在堆上,例如new或者malloc出來的東西
- //但是現在的系統比如Linux和windows都提供了線程本地存儲空間,也就是這個存儲空間是和線程相關的,一個線程內有一個內部存儲空間,這樣的話我把線程相關的東西就存儲到
- //這個線程的TLS中,就不用放在堆上而進行同步操作了。
- private static final ThreadLocal sThreadLocal = new ThreadLocal();
- //消息隊列,MessageQueue,看名字就知道是個queue..
- final MessageQueue mQueue;
- volatile boolean mRun;
- //和本looper相關的那個線程,初始化為null
- Thread mThread;
- private Printer mLogging = null;
- //static變量,代表一個UI Process(也可能是service吧,這裡默認就是UI)的主線程
- private static Looper mMainLooper = null;
-
- /** 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()}.
- */
- //往TLS中設上這個Looper對象的,如果這個線程已經設過了looper的話就會報錯
- //這說明,一個線程只能設一個looper
- 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()}
- */
- //由framework設置的UI程序的主消息循環,注意,這個主消息循環是不會主動退出的
- //
- public static final void prepareMainLooper() {
- prepare();
- setMainLooper(myLooper());
- //判斷主消息循環是否能退出....
- //通過quit函數向looper發出退出申請
- if (Process.supportsProcesses()) {
- 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 final Looper getMainLooper() {
- return mMainLooper;
- }
-
- /**
- * Run the message queue in this thread. Be sure to call
- * {@link #quit()} to end the loop.
- */
- //消息循環,整個程序就在這裡while了。
- //這個是static函數喔!
- public static final void loop() {
- Looper me = myLooper();//從該線程中取出對應的looper對象
- MessageQueue queue = me.mQueue;//取消息隊列對象...
- while (true) {
- Message msg = queue.next(); // might block取消息隊列中的一個待處理消息..
- //if (!me.mRun) {//是否需要退出?mRun是個volatile變量,跨線程同步的,應該是有地方設置它。
- // break;
- //}
- if (msg != null) {
- if (msg.target == null) {
- // No target is a magic identifier for the quit message.
- return;
- }
- if (me.mLogging!= null) me.mLogging.println(
- ">>>>> Dispatching to " + msg.target + " "
- + msg.callback + ": " + msg.what
- );
- msg.target.dispatchMessage(msg);
- if (me.mLogging!= null) me.mLogging.println(
- "<<<<< Finished to " + msg.target + " "
- + msg.callback);
- msg.recycle();
- }
- }
- }
-
- /**
- * Return the Looper object associated with the current thread. Returns
- * null if the calling thread is not associated with a Looper.
- */
- //返回和線程相關的looper
- public static final Looper myLooper() {
- return (Looper)sThreadLocal.get();
- }
-
- /**
- * Control logging of messages as they are processed by this Looper. If
- * enabled, a log message will be written to <var>printer</var>
- * at the beginning and ending of each message dispatch, identifying the
- * target Handler and message contents.
- *
- * @param printer A Printer object that will receive log messages, or
- * null to disable message logging.
- */
- //設置調試輸出對象,looper循環的時候會打印相關信息,用來調試用最好了。
- public void setMessageLogging(Printer printer) {
- mLogging = printer;
- }
-
- /**
- * Return the {@link MessageQueue} object associated with the current
- * thread. This must be called from a thread running a Looper, or a
- * NullPointerException will be thrown.
- */
- public static final MessageQueue myQueue() {
- return myLooper().mQueue;
- }
- //創建一個新的looper對象,
- //內部分配一個消息隊列,設置mRun為true
- private Looper() {
- mQueue = new MessageQueue();
- mRun = true;
- mThread = Thread.currentThread();
- }
-
- public void quit() {
- Message msg = Message.obtain();
- // NOTE: By enqueueing directly into the message queue, the
- // message is left with a null target. This is how we know it is
- // a quit message.
- mQueue.enqueueMessage(msg, 0);
- }
-
- /**
- * Return the Thread associated with this Looper.
- */
- public Thread getThread() {
- return mThread;
- }
- //後面就簡單了,打印,異常定義等。
- public void dump(Printer pw, String prefix) {
- pw.println(prefix + this);
- pw.println(prefix + "mRun=" + mRun);
- pw.println(prefix + "mThread=" + mThread);
- pw.println(prefix + "mQueue=" + ((mQueue != null) ? mQueue : "(null"));
- if (mQueue != null) {
- synchronized (mQueue) {
- Message msg = mQueue.mMessages;
- int n = 0;
- while (msg != null) {
- pw.println(prefix + " Message " + n + ": " + msg);
- n++;
- msg = msg.next;
- }
- pw.println(prefix + "(Total messages: " + n + ")");
- }
- }
- }
-
- public String toString() {
- return "Looper{"
- + Integer.toHexString(System.identityHashCode(this))
- + "}";
- }
-
- static class HandlerException extends Exception {
-
- HandlerException(Message message, Throwable cause) {
- super(createMessage(cause), cause);
- }
-
- static String createMessage(Throwable cause) {
- String causeMsg = cause.getMessage();
- if (causeMsg == null) {
- causeMsg = cause.toString();
- }
- return causeMsg;
- }
- }
- }