<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Calvin's Tech Space

    成于堅忍,毀于浮躁

       :: 首頁 :: 聯系 :: 聚合  :: 管理
    轉載地址:http://blog.csdn.net/jinlking/archive/2009/07/09/4333456.aspx

    在Android下面也有多線程的概念,在C/C++中,子線程可以是一個函數,一般都是一個帶有循環的函數,來處理某些數據,優先線程只是一個復雜的運算過程,所以可能不需要while循環,運算完成,函數結束,線程就銷毀。對于那些需要控制的線程,一般我們都是和互斥鎖相互關聯,從而來控制線程 的進度,一般我們創建子線程,一種線程是很常見的,那就是帶有消息循環的線程。

    消息循環是一個很有用的線程方式,曾經自己用C在Linux下面實現一個消息循環的機制,往消息隊列里添加數據,然后異步的等待消息的返回。當消息隊列為空的時候就會掛起線程,等待新的消息的加入。這是一個很通用的機制。

    在Android,這里的線程分為有消息循環的線程和沒有消息循環的線程,有消息循環的線程一般都會有一個Looper,這個是android的新概念。我們的主線程(UI線程)就是一個消息循環的線程。針對這種消息循環的機制,我們引入一個新的機制Handler,我們有消息循環,就要往消息循環里面發送相應的消息,自定義消息一般都會有自己對應的處理,消息的發送和清除,消息的的處理,把這些都封裝在Handle里面,注意Handle只是針對那 些有Looper的線程,不管是UI線程還是子線程,只要你有Looper,我就可以往你的消息隊列里面添加東西,并做相應的處理。

    但是這里還有一點,就是只要是關于UI相關的東西,就不能放在子線程中,因為子線程是不能操作UI的,只能進行數據、系統等其他非UI的操作。

    那么什么情況下面我們的子線程才能看做是一個有Looper的線程呢?我們如何得到它Looper的句柄呢?

    Looper.myLooper();獲得當前的Looper

    Looper.getMainLooper () 獲得UI線程的Lopper

    我們看看Handle的初始化函數,如果沒有參數,那么他就默認使用的是當前的Looper,如果有Looper參數,就是用對應的線程的Looper。

    如果一個線程中調用Looper.prepare(),那么系統就會自動的為該線程建立一個消息隊列,然后調用 Looper.loop();之后就進入了消息循環,這個之后就可以發消息、取消息、和處理消息。這個如何發送消息和如何處理消息可以在其他的線程中通過 Handle來做,但前提是我們的Handle知道這個子線程的Looper,但是你如果不是在子線程運行 Looper.myLooper(),一般是得不到子線程的looper的。

    public void run() {
                synchronized (mLock) {
                    Looper.prepare();
                   //do something
                }
                Looper.loop();
            }

    所以很多人都是這樣做的:我直接在子線程中新建handle,然后在子線程中發送消息,這樣的話就失去了我們多線程的意義了。
     1 class myThread extends Thread{
     2 
     3              private EHandler mHandler ;
     4 
     5              public void run() {
     6 
     7                  Looper myLooper, mainLooper;
     8 
     9                  myLooper = Looper.myLooper ();
    10 
    11                 mainLooper = Looper.getMainLooper ();
    12 
    13                 String obj;
    14 
    15                 if (myLooper == null ){
    16 
    17                          mHandler = new EHandler(mainLooper);
    18 
    19                          obj = "current thread has no looper!" ;
    20 
    21                 }
    22 
    23                 else {
    24 
    25                      mHandler = new EHandler(myLooper);
    26 
    27                      obj = "This is from current thread." ;
    28 
    29                 }
    30 
    31                 mHandler .removeMessages(0);
    32 
    33                 Message m = mHandler .obtainMessage(111, obj);
    34 
    35                 mHandler .sendMessage(m);
    36 
    37              }
    38 
    39   }

    可以讓其他的線程來控制我們的handle,可以把 private EHandler mHandler ;放在外面,這樣我們的發消息和處理消息都可以在外面來定義,這樣增加程序代碼的美觀,結構更加清晰。

    對如任何的Handle,里面必須要重載一個函數

    public void handleMessage(Message msg)

    這個函數就是我們的消息處理,如何處理,這里完全取決于你,然后通過 obtainMessage和 sendMessage等來生成和發送消息, removeMessages(0)來清除消息隊列。Google真是太智慧了,這種框架的產生,我們寫代碼更加輕松了。

    有的時候,我們的子線程想去改變UI了,這個時候千萬不要再子線程中去修改,獲得UI線程的Looper,然后發送消息即可。

    我們來看看高煥堂的代碼:

    // class ac01 extends Activity {

              // ………

                  public void onClick(View v) {

                         switch (v.getId()){

                         case 101:

                                      t = new myThread();

                                t .start();

                              break ;

                         case 102:

                      finish();

                                    break ;

                         }

               }

    //------------------------------------------------------            

    class EHandler extends Handler {

                       public EHandler(Looper looper) {

                           super (looper);

                       }

                       @Override

                       public void handleMessage(Message msg) {

                          tv .setText((String)msg. obj );

                   }

               }

    //------------------------------------------------------            

    class myThread extends Thread{

                 private EHandler mHandler ;

                 public void run() {

                    Looper myLooper, mainLooper;

                    myLooper = Looper.myLooper ();

                    mainLooper = Looper.getMainLooper ();

                    String obj;

                    if (myLooper == null ){

                            mHandler = new EHandler(mainLooper);

                            obj = "current thread has no looper!" ;

                    }

                    else {

                         mHandler = new EHandler(myLooper);

                         obj = "This is from current thread." ;

                    }

                    mHandler .removeMessages(0);

                    Message m = mHandler .obtainMessage(1, 1, 1, obj);

                    mHandler .sendMessage(m);

                 }

      }

    }

    完全是不知所云,一坨狗屎。我們來看,在上面的run里面

    Looper myLooper, mainLooper;

    myLooper = Looper.myLooper (); //很明顯這個會返回空,因為你還沒有 prepare,不會返回Looper。

    mainLooper = Looper.getMainLooper ();

    建議大家在看Looper的時候不要看高煥堂的書,感覺他也不是很懂,倒還把我搞糊涂了。講了那么多,完全是他自己的理解,他自己的理解很是復雜,關鍵的是把簡單的問題復雜化,并且復雜之后的東西還是錯的。我們看看Goole Music App的源代碼。

    在MediaPlaybackActivity.java中,我們可以看一下再OnCreate中的有這樣的兩句:

            mAlbumArtWorker = new Worker("album art worker");
            mAlbumArtHandler = new AlbumArtHandler(mAlbumArtWorker.getLooper());

    很明顯這兩句,是構建了一個子線程。并且這個子線程還是Looper的子線程,這里很牛逼的使用了 mAlbumArtWorker.getLooper()這個函數,因為我們知道,我們能夠得到子線程的Looper的途徑只有一個:就是在子線程中調用 Looper.myLooper (),并且這個函數還要在我們perpare之后調用才能得到正確的Looper,但是他這里用了一個這樣的什么東東 getLooper,不知道它是如何實現的?

    這里有一個大概的思路,我們在子線程的的prepare之后調用 myLooper ()這個方法,然后保存在一個成員變量中,這個getLooper就返回這個東西,但是這里會碰到多線程的一個很突出的問題,同步。我們在父線程中調用 mAlbumArtWorker.getLooper(),但是想要這個返回正確的looper就必須要求我們的子線程運行了prepare,但是這個東 西實在子線程運行的,我們如何保證呢?
     
    我們看Google是如何實現的?

     
      private class Worker implements Runnable {
            
    private final Object mLock = new Object();
            
    private Looper mLooper;
           
            
    /**
             * Creates a worker thread with the given name. The thread
             * then runs a {
    @link android.os.Looper}.
             * 
    @param name A name for the new thread

             
    */
            Worker(String name) {
                Thread t 
    = new Thread(nullthis, name);
                t.setPriority(Thread.MIN_PRIORITY);
                t.start();
                
    synchronized (mLock) {
                    
    while (mLooper == null) {
                        
    try {
                            mLock.wait();
                        } 
    catch (InterruptedException ex) {
                        }
                    }
                }
            }
           
            
    public Looper getLooper() {
                
    return mLooper;
            }
           
            
    public void run() {
                
    synchronized (mLock) {
                    Looper.prepare();
                    mLooper 
    = Looper.myLooper();
                    mLock.notifyAll();
                }
                Looper.loop();
            }
           
            
    public void quit() {
                mLooper.quit();
            }
        }

    我們知道,一個線程類的構造函數是在主線程中完成的,所以在我們的 Worker的構造函數中我們創佳一個線程,然后讓這個線程運行,這一這個線程的創建是指定一個 Runnabl,這里就是我們的Worker本身,在主線程調用 t.start();,這后,我們子線程已經創建,并且開始執行work的run方法。然后下面的代碼很藝術:

    synchronized (mLock) {
                    while (mLooper == null) {
                        try {
                            mLock.wait();
                        } catch (InterruptedException ex) {
                        }
                    }
                }

    我們開始等待我們的子線程給mLooper賦值,如果不賦值我們就繼續等,然后我們的子線程在運行run方法之后,在給 mLooper賦值之后,通知worker夠著函數中的wait,然后我們的構造函數才能完成,所以我們說:

    mAlbumArtWorker = new Worker("album art worker");

    這句本身就是阻塞的,它創建了一個子線程,開啟了子線程,并且等待子線程給mLooper賦值,賦值完成之后,這個函數才返回,這樣才能保證我們的子線程的Looper的獲取絕對是正確的,這個構思很有創意。值得借鑒。

    PS:
    1、發送消息并不會阻塞線程,而處理消息時會阻塞線程,這是因為Handler 處理完一個 Message 對象才會接著去取下面一個消息進行處理。
    Handler對于Message的處理不是并發的。一個Looper 只有處理完一條Message才會讀取下一條,所以消息的處理是阻塞形式的,如果在handler里做耗時的操作,則調用者線程會阻塞。但是如果用不同的Looper則能達到并發的目的。(http://windywindy.javaeye.com/blog/464185

    2、Android提供了一個HandlerThread來實現并發處理message的目的,HandlerThread在實現上與Music應用的Worker類相似。

    參考:
    posted on 2010-11-29 14:55 calvin 閱讀(3213) 評論(0)  編輯  收藏 所屬分類: Android
    主站蜘蛛池模板: 亚洲精品动漫在线| a级毛片免费播放| 国产精品成人69XXX免费视频| 免费看的黄色大片| 久久久久亚洲国产| 国产精品无码免费播放| 日韩亚洲人成在线| 日韩免费观看的一级毛片| 亚洲成AV人片在WWW| 成年女人免费视频播放体验区| 亚洲av无码电影网| 国产免费AV片在线观看| 日本牲交大片免费观看| 亚洲国产精品美女久久久久| 麻豆成人精品国产免费| 粉色视频成年免费人15次| 午夜国产精品免费观看| 中文字幕专区在线亚洲| 国产男女爽爽爽免费视频| 亚洲自偷自偷在线制服| a级毛片免费全部播放无码| 亚洲国产精品一区二区久久| 麻豆成人久久精品二区三区免费| 亚洲成a人片在线观看久| 一级A毛片免费观看久久精品 | 亚洲va中文字幕无码久久不卡| 男女作爱在线播放免费网站| 九月婷婷亚洲综合在线| 亚洲Av高清一区二区三区| 成人男女网18免费视频| 成年大片免费高清在线看黄| 亚洲动漫精品无码av天堂| 中文字幕免费在线观看动作大片| 亚洲成AV人在线播放无码| 四虎精品视频在线永久免费观看| 亚洲精品无码永久在线观看男男| 亚洲国产精品成人久久蜜臀| 日韩免费人妻AV无码专区蜜桃| 亚洲av无码专区在线观看亚| 最好免费观看韩国+日本| xxxxx做受大片视频免费|