久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Android Looper和Handler分析

 gearss 2016-04-21

 第一次接觸Android應(yīng)用程序(這里指的是Java層的UI程序,,也難怪了,,Google放出的API就只支持JAVA應(yīng)用程序了),,很難搞明白內(nèi)部是如何實現(xiàn)的。但是,,從原理上分析,,應(yīng)該是有一個消息循環(huán),一個消息隊列,,然后主線程不斷得從消息隊列中取得消息并處理之,。

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

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

那怎么往這個消息隊列中發(fā)送消息呢?,?調(diào)用looper的static函數(shù)myQueue可以獲得消息隊列,,這樣你就可用自己往里邊插入消息了。不過這種方法比較麻煩,,這個時候handler類就發(fā)揮作用了,。先來看看handler的代碼,就明白了,。

  1. class Handler{  
  2. ..........  
  3. //handler默認(rèn)構(gòu)造函數(shù)  
  4. public Handler() {  
  5. //這個if是干嘛用的暫時還不明白,,涉及到j(luò)ava的深層次的內(nèi)容了應(yīng)該  
  6.         if (FIND_POTENTIAL_LEAKS) {  
  7.             final Class<? extends Handler> klass = getClass();  
  8.             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&  
  9.                     (klass.getModifiers() & Modifier.STATIC) == 0) {  
  10.                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +  
  11.                     klass.getCanonicalName());  
  12.             }  
  13.         }  
  14. //獲取本線程的looper對象  
  15. //如果本線程還沒有設(shè)置looper,這回拋異常  
  16.         mLooper = Looper.myLooper();  
  17.         if (mLooper == null) {  
  18.             throw new RuntimeException(  
  19.                 "Can't create handler inside thread that has not called Looper.prepare()");  
  20.         }  
  21. //無恥啊,,直接把looper的queue和自己的queue搞成一個了  
  22. //這樣的話,,我通過handler的封裝機(jī)制加消息的話,就相當(dāng)于直接加到了looper的消息隊列中去了  
  23.         mQueue = mLooper.mQueue;  
  24.         mCallback = null;  
  25.     }  
  26. //還有好幾種構(gòu)造函數(shù),,一個是帶callback的,,一個是帶looper的  
  27. //由外部設(shè)置looper  
  28.     public Handler(Looper looper) {  
  29.         mLooper = looper;  
  30.         mQueue = looper.mQueue;  
  31.         mCallback = null;  
  32.     }  
  33. // 帶callback的,一個handler可以設(shè)置一個callback,。如果有callback的話,,  
  34. //凡是發(fā)到通過這個handler發(fā)送的消息,都有callback處理,,相當(dāng)于一個總的集中處理  
  35. //待會看dispatchMessage的時候再分析  
  36. public Handler(Looper looper, Callback callback) {  
  37.         mLooper = looper;  
  38.         mQueue = looper.mQueue;  
  39.         mCallback = callback;  
  40.     }  
  41. //  
  42. //通過handler發(fā)送消息  
  43. //調(diào)用了內(nèi)部的一個sendMessageDelayed  
  44. public final boolean sendMessage(Message msg)  
  45.     {  
  46.         return sendMessageDelayed(msg, 0);  
  47.     }  
  48. //FT,,又封裝了一層,這回是調(diào)用sendMessageAtTime了  
  49. //因為延時時間是基于當(dāng)前調(diào)用時間的,,所以需要獲得絕對時間傳遞給sendMessageAtTime  
  50. public final boolean sendMessageDelayed(Message msg, long delayMillis)  
  51.     {  
  52.         if (delayMillis < 0) {  
  53.             delayMillis = 0;  
  54.         }  
  55.         return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
  56.     }  
  57.   
  58.   
  59. public boolean sendMessageAtTime(Message msg, long uptimeMillis)  
  60.     {  
  61.         boolean sent = false;  
  62.         MessageQueue queue = mQueue;  
  63.         if (queue != null) {  
  64. //把消息的target設(shè)置為自己,,然后加入到消息隊列中  
  65. //對于隊列這種數(shù)據(jù)結(jié)構(gòu)來說,,操作比較簡單了  
  66.             msg.target = this;  
  67.             sent = queue.enqueueMessage(msg, uptimeMillis);  
  68.         }  
  69.         else {  
  70.             RuntimeException e = new RuntimeException(  
  71.                 this + " sendMessageAtTime() called with no mQueue");  
  72.             Log.w("Looper", e.getMessage(), e);  
  73.         }  
  74.         return sent;  
  75.     }  
  76. //還記得looper中的那個消息循環(huán)處理嗎  
  77. //從消息隊列中得到一個消息后,會調(diào)用它的target的dispatchMesage函數(shù)  
  78. //message的target已經(jīng)設(shè)置為handler了,,所以  
  79. //最后會轉(zhuǎn)到handler的msg處理上來  
  80. //這里有個處理流程的問題  
  81. public void dispatchMessage(Message msg) {  
  82. //如果msg本身設(shè)置了callback,,則直接交給這個callback處理了  
  83.         if (msg.callback != null) {  
  84.             handleCallback(msg);  
  85.         } else {  
  86. //如果該handler的callback有的話,則交給這個callback處理了---相當(dāng)于集中處理  
  87.           if (mCallback != null) {  
  88.                 if (mCallback.handleMessage(msg)) {  
  89.                     return;  
  90.                 }  
  91.            }  
  92. //否則交給派生處理,基類默認(rèn)處理是什么都不干  
  93.             handleMessage(msg);  
  94.         }  
  95.     }  
  96. ..........  
  97. }  

 講了這么多,,該怎么創(chuàng)建和使用一個帶消息循環(huán)的線程呢,?

  1. //假設(shè)在onCreate中創(chuàng)建一個線程  
  2. //不花時間考慮代碼的完整和嚴(yán)謹(jǐn)性了,以講述原理為主,。  
  3. ....  
  4.   
  5. ... onCreate(...){  
  6.   
  7. //難點(diǎn)是如何把a(bǔ)ndroid中的looper和java的thread弄到一起去,。  
  8. //而且還要把隨時取得這個looper用來創(chuàng)建handler  
  9. //最簡單的辦法就是從Thread派生一個  
  10. class ThreadWithMessageHandle extends Thread{  
  11.   //重載run函數(shù)  
  12.   Looper myLooper = null;  
  13.   run(){  
  14.   Looper.prepare();//將Looper設(shè)置到這個線程中  
  15.   myLooper = Looper.myLooper();  
  16.   Looper.loop();開啟消息循環(huán)  
  17. }  
  18.   
  19.  ThreadWithMessageHandle  threadWithMgs = new ThreadWithMessageHandle();  
  20.  threadWithMsg.start();  
  21.  Looper looper = threadWithMsg.myLooper;//  
  22. //這里有個問題.threadWithMgs中的myLooper可能此時為空  
  23. //需要同步處理一下  
  24. //或者像API文檔中的那樣,把handler定義到ThreadWithMessageHandle到去,。  
  25. //外線程獲得這個handler的時候仍然要注意同步的問題,,因為handler的創(chuàng)建是在run中的  
  26.  Handler threadHandler = new Handler(looper);  
  27.  threadHandler.sendMessage(...)  
  28. }  
  29.   
  30.   
  31. }  
  32.   
  33.   
  34.   
  35. ...  

好了,handler和looper的分析就都這了,,其實原理挺簡單的,。

 

 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多