Android多線程學習執行個體詳解_Android

來源:互聯網
上載者:User

本文執行個體分析了Android多線程。分享給大家供大家參考,具體如下:

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

訊息迴圈是一個很有用的線程方式,曾經自己用C在Linux下面實現一個訊息迴圈的機制,往訊息佇列裡添加資料,然後非同步等待訊息的返回。當訊息佇列為空白的時候就會掛起線程,等待新的訊息的加入。這是一個很通用的機制。

在Android,這裡的線程分為有訊息迴圈的線程和沒有訊息迴圈的線程,有訊息迴圈的線程一般都會有一個Looper,這個事android的新 概念。我們的主線程(UI線程)就是一個訊息迴圈的線程。針對這種訊息迴圈的機制,我們引入一個新的機制Handle,我們有訊息迴圈,就要往訊息迴圈裡 面發送相應的訊息,自訂訊息一般都會有自己對應的處理,訊息的發送和清除,訊息的的處理,把這些都封裝在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來做,但前提是我們的Hanle知道這個子線程的Looper,但是你如果不是在子線程運行 Looper.myLooper(),一般是得不到子線程的looper的。

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

所以很多人都是這樣做的:我直接在子線程中建立handle,然後在子線程中發送訊息,這樣的話就失去了我們多線程的意義了。

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);   }}

可以讓其他的線程來控制我們的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(null, this, 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的擷取絕對是正確的,這個構思很有創意。值得借鑒。

更多關於Android相關內容感興趣的讀者可查看本站專題:《Android線程與訊息機制用法總結》、《Android開發入門與進階教程》、《Android調試技巧與常見問題解決方案匯總》、《Android多媒體操作技巧匯總(音頻,視頻,錄音等)》、《Android基本組件用法總結》、《Android視圖View技巧總結》、《Android布局layout技巧總結》及《Android控制項用法總結》

希望本文所述對大家Android程式設計有所協助。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.