歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android Looper和Handler分析

Android Looper和Handler分析

日期:2017/3/1 10:18:29   编辑:Linux編程
第一次接觸Android應用程序(這裡指的是JAVA層的UI程序,也難怪了,Google放出的API就只支持JAVA應用程序了),很難搞明白內部是如何實現的。但是,從原理上分析,應該是有一個消息循環,一個消息隊列,然後主線程不斷得從消息隊列中取得消息並處理之。

然而,google封裝得太厲害了,所以一時半會還是搞不清楚到底是怎麼做的。本文將分析android內的looper,這個是用來封裝消息循環和消息隊列的一個類,handler其實可以看做是一個工具類,用來向消息隊列中插入消息的。好比是Windows API的SendMessage中的HANDLE,這個handle是窗口句柄。

  1. //Looper類分析
  2. //沒找到合適的分析代碼的辦法,只能這麼來了。每個重要行的上面都會加上注釋
  3. //功能方面的代碼會在代碼前加上一段分析
  4. public class Looper {
  5. //static變量,判斷是否打印調試信息。
  6. private static final boolean DEBUG = false;
  7. private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
  8. // sThreadLocal.get() will return null unless you've called prepare().
  9. //線程本地存儲功能的封裝,TLS,thread local storage,什麼意思呢?因為存儲要麼在棧上,例如函數內定義的內部變量。要麼在堆上,例如new或者malloc出來的東西
  10. //但是現在的系統比如Linux和windows都提供了線程本地存儲空間,也就是這個存儲空間是和線程相關的,一個線程內有一個內部存儲空間,這樣的話我把線程相關的東西就存儲到
  11. //這個線程的TLS中,就不用放在堆上而進行同步操作了。
  12. private static final ThreadLocal sThreadLocal = new ThreadLocal();
  13. //消息隊列,MessageQueue,看名字就知道是個queue..
  14. final MessageQueue mQueue;
  15. volatile boolean mRun;
  16. //和本looper相關的那個線程,初始化為null
  17. Thread mThread;
  18. private Printer mLogging = null;
  19. //static變量,代表一個UI Process(也可能是service吧,這裡默認就是UI)的主線程
  20. private static Looper mMainLooper = null;
  21. /** Initialize the current thread as a looper.
  22. * This gives you a chance to create handlers that then reference
  23. * this looper, before actually starting the loop. Be sure to call
  24. * {@link #loop()} after calling this method, and end it by calling
  25. * {@link #quit()}.
  26. */
  27. //往TLS中設上這個Looper對象的,如果這個線程已經設過了looper的話就會報錯
  28. //這說明,一個線程只能設一個looper
  29. public static final void prepare() {
  30. if (sThreadLocal.get() != null) {
  31. throw new RuntimeException("Only one Looper may be created per thread");
  32. }
  33. sThreadLocal.set(new Looper());
  34. }
  35. /** Initialize the current thread as a looper, marking it as an application's main
  36. * looper. The main looper for your application is created by the Android environment,
  37. * so you should never need to call this function yourself.
  38. * {@link #prepare()}
  39. */
  40. //由framework設置的UI程序的主消息循環,注意,這個主消息循環是不會主動退出的
  41. //
  42. public static final void prepareMainLooper() {
  43. prepare();
  44. setMainLooper(myLooper());
  45. //判斷主消息循環是否能退出....
  46. //通過quit函數向looper發出退出申請
  47. if (Process.supportsProcesses()) {
  48. myLooper().mQueue.mQuitAllowed = false;
  49. }
  50. }
  51. private synchronized static void setMainLooper(Looper looper) {
  52. mMainLooper = looper;
  53. }
  54. /** Returns the application's main looper, which lives in the main thread of the application.
  55. */
  56. public synchronized static final Looper getMainLooper() {
  57. return mMainLooper;
  58. }
  59. /**
  60. * Run the message queue in this thread. Be sure to call
  61. * {@link #quit()} to end the loop.
  62. */
  63. //消息循環,整個程序就在這裡while了。
  64. //這個是static函數喔!
  65. public static final void loop() {
  66. Looper me = myLooper();//從該線程中取出對應的looper對象
  67. MessageQueue queue = me.mQueue;//取消息隊列對象...
  68. while (true) {
  69. Message msg = queue.next(); // might block取消息隊列中的一個待處理消息..
  70. //if (!me.mRun) {//是否需要退出?mRun是個volatile變量,跨線程同步的,應該是有地方設置它。
  71. // break;
  72. //}
  73. if (msg != null) {
  74. if (msg.target == null) {
  75. // No target is a magic identifier for the quit message.
  76. return;
  77. }
  78. if (me.mLogging!= null) me.mLogging.println(
  79. ">>>>> Dispatching to " + msg.target + " "
  80. + msg.callback + ": " + msg.what
  81. );
  82. msg.target.dispatchMessage(msg);
  83. if (me.mLogging!= null) me.mLogging.println(
  84. "<<<<< Finished to " + msg.target + " "
  85. + msg.callback);
  86. msg.recycle();
  87. }
  88. }
  89. }
  90. /**
  91. * Return the Looper object associated with the current thread. Returns
  92. * null if the calling thread is not associated with a Looper.
  93. */
  94. //返回和線程相關的looper
  95. public static final Looper myLooper() {
  96. return (Looper)sThreadLocal.get();
  97. }
  98. /**
  99. * Control logging of messages as they are processed by this Looper. If
  100. * enabled, a log message will be written to <var>printer</var>
  101. * at the beginning and ending of each message dispatch, identifying the
  102. * target Handler and message contents.
  103. *
  104. * @param printer A Printer object that will receive log messages, or
  105. * null to disable message logging.
  106. */
  107. //設置調試輸出對象,looper循環的時候會打印相關信息,用來調試用最好了。
  108. public void setMessageLogging(Printer printer) {
  109. mLogging = printer;
  110. }
  111. /**
  112. * Return the {@link MessageQueue} object associated with the current
  113. * thread. This must be called from a thread running a Looper, or a
  114. * NullPointerException will be thrown.
  115. */
  116. public static final MessageQueue myQueue() {
  117. return myLooper().mQueue;
  118. }
  119. //創建一個新的looper對象,
  120. //內部分配一個消息隊列,設置mRun為true
  121. private Looper() {
  122. mQueue = new MessageQueue();
  123. mRun = true;
  124. mThread = Thread.currentThread();
  125. }
  126. public void quit() {
  127. Message msg = Message.obtain();
  128. // NOTE: By enqueueing directly into the message queue, the
  129. // message is left with a null target. This is how we know it is
  130. // a quit message.
  131. mQueue.enqueueMessage(msg, 0);
  132. }
  133. /**
  134. * Return the Thread associated with this Looper.
  135. */
  136. public Thread getThread() {
  137. return mThread;
  138. }
  139. //後面就簡單了,打印,異常定義等。
  140. public void dump(Printer pw, String prefix) {
  141. pw.println(prefix + this);
  142. pw.println(prefix + "mRun=" + mRun);
  143. pw.println(prefix + "mThread=" + mThread);
  144. pw.println(prefix + "mQueue=" + ((mQueue != null) ? mQueue : "(null"));
  145. if (mQueue != null) {
  146. synchronized (mQueue) {
  147. Message msg = mQueue.mMessages;
  148. int n = 0;
  149. while (msg != null) {
  150. pw.println(prefix + " Message " + n + ": " + msg);
  151. n++;
  152. msg = msg.next;
  153. }
  154. pw.println(prefix + "(Total messages: " + n + ")");
  155. }
  156. }
  157. }
  158. public String toString() {
  159. return "Looper{"
  160. + Integer.toHexString(System.identityHashCode(this))
  161. + "}";
  162. }
  163. static class HandlerException extends Exception {
  164. HandlerException(Message message, Throwable cause) {
  165. super(createMessage(cause), cause);
  166. }
  167. static String createMessage(Throwable cause) {
  168. String causeMsg = cause.getMessage();
  169. if (causeMsg == null) {
  170. causeMsg = cause.toString();
  171. }
  172. return causeMsg;
  173. }
  174. }
  175. }
Copyright © Linux教程網 All Rights Reserved