Android 中Thread,Handler,Loop學習

來源:互聯網
上載者:User

標籤:

1.先看一下最簡單的進度條樣本

EG:

package com.sxz.android.thread;

import java.util.concurrent.atomic.AtomicBoolean;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ProgressBar;
public class HandlerDemo extends Activity {

    ProgressBar bar;
    AtomicBoolean isRunning = new AtomicBoolean(false);
    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            bar.incrementProgressBy(5);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_progressbar);
        bar = (ProgressBar) findViewById(R.id.progressBar1);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Thread myThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for (int i = 0; i < 20 && isRunning.get(); i++) {
                        Message msg = mHandler.obtainMessage();
                        Thread.sleep(500);
                        msg.sendToTarget();
                    }

                } catch (Throwable t)
                {
                }
            }
        });

        isRunning.set(true);
        myThread.start();
    }

    @Override
    protected void onStop() {
        super.onStop();
        isRunning.set(false);
    }
}

2. 基本概念

MessageQueue 訊息佇列,存放訊息的地方,按照FIFO規則執行,每一個線程只可以擁有一個MessageQueue,在建立 Looper 對象會建立一個MessageQueue對象。而MessageQueue

都會有一個對應的 Handler,Handler會向 MessageQueue通過兩種方法發送訊息.

① sendMessage. 通過 sendMessage發送的是一個 message 對象,會被 Handler的 handleMessage() 函數處理。
② post 通過 post 方法發送的是一個 runnable 對象,則會自己執行。

這兩種訊息都會插在 MessageQueue 隊尾並按先進先出的方式執行.但是通過這兩種方法發送出去的訊息執行的方式略有不同.

Message 訊息對象,MessageQueue中存放的對象。一個 MessageQueue中可以包含多個Message 對象。可以通過 Message.obtain() 或者 Handler.obtainMessage() 擷取 Message 對象.但是這並不一定是直接建立一個新的執行個體.而是先從訊息池中看有沒有可用的 Message執行個體。存在則直接取出後返回這個執行個體。如果訊息池中沒有可用的 Message 執行個體,則用給定的參數建立一個Message 對象。調用 removeMessage()時,將 Message 從 MessageQueue 中刪除,同時放入到訊息池中。
訊息,其實可以理解為線程間交流的資訊,處理資料後台線程需要更新 UI,則發送Message內含一些資料給 UI線程.

Looper 操作 MessageQueue,一個 Looper 對應一個 MessageQueue.通過調用 Looper.myLooper() 可以擷取當前線程的 Looper對象.Looper 從 MessageQueue中取出 Message然後, 交由Handler的 handleMessage() 進行處理。處理完成後,調用 Message.recycle()將其放入訊息池中.


Looper 是每條線程裡的 MessageQueue的管家。Android沒有 Gloabal 的 MessageQueue,而 Android 會自動替主線程(UI線程) 建立MessageQueue,但在子線程裡並沒有建立MessageQueue。所以調用 Looper.getMainLooper() 得到的主線程Looper不為 NULL,但是調用Looper.myLooper()得到的Looper就有可能為 NULL。

 

總結:幾者之間的關係:


Handler 訊息的處理者。

handler 負責將需要傳遞的資訊封裝成 Message 對象,

然後調用 sendMessage() 方法將訊息放入 MessageQueue中,

當MessageQueue迴圈到該 Message,

調用相應的handler 對象的 handleMessage() 方法對其進行處理。

Handler 都可以共用同一個 Looper 和 MessageQueue.

 

3. handler.post(r)同一個線程的疑惑

handler.post(r);是把r加到訊息佇列,但並未開闢新線程。等到訊息被取出時才執行。

package com.lei.handlethread;import android.os.Bundle;import android.os.Handler;import android.app.Activity;import android.view.Menu;import android.widget.Button;public class MainActivity extends Activity { private Button btn = null; private Handler handler = new Handler(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); handler.post(r); setContentView(R.layout.activity_main); btn = (Button)findViewById(R.id.hello);// 用來驗證setContentView()先執行的。 
String s=(String) btn.getText();//
System.out.println(s); System.out.println("activity--->"+Thread.currentThread().getId()); System.out.println("Activityname--->"+Thread.currentThread().getName()); } Runnable r = new Runnable() { public void run() { System.out.println("handler--->"+Thread.currentThread().getId()); System.out.println("handlername--->"+Thread.currentThread().getName()); try { Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; }}

運行結果:logCat先列印如下資訊。程式運行介面過10s顯示TextView文字。

解釋:

main線程從訊息泵中取出一個訊息,處理(執行相關函數),然後再取一個,處理。所以onCreate是某一訊息處理中的執行,其中post一個訊息,只是把訊息排入佇列了,還沒執行新訊息,什麼時候執行?要等前一個訊息處理完,再次從訊息泵中取訊息處理時,它才被執行。所以先是main的system.out,再是post的system.out

相比之下,sendMessage是同步執行,用handler.sendMessage,那順序就變了。

至於setContentView(R.layout.activity_main);肯定是最先執行,程式介面最先開啟了,但是介面空間要等到Activity的Resume(即互動階段)階段才會顯示。

通過擷取介面空間ID,在Log中列印空間內容就可驗證。

Android 中Thread,Handler,Loop學習

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.