Handler系列之建立子線程Handler

  上一篇我介紹了Handler機制的工做原理,默認狀況下,ActivityThread類爲咱們建立的了主線程的Looper和消息隊列,因此當你建立Handler以後發送消息的時候,消息的輪訓和handle都是在ui線程進行的。這種狀況屬於子線程給主線程發消息,通知主線程更新ui...等,那麼反過來,怎麼才能讓主線程給子線程發消息,通知子線程作一些耗時邏輯??ide

  以前的學習咱們知道,Android的消息機制遵循三個步驟:oop

    1  建立當前線程的Looper  學習

    2  建立當前線程的Handler ui

    3  調用當前線程Looper對象的loop方法this

  看過以前文章的朋友會注意到,本篇我特地強調了「當前線程」。是的以前咱們學習的不少都是Android未咱們作好了的,譬如:建立主線程的Looper、主線程的消息隊列...就連咱們使用的handler也是主線程的。那麼若是我想建立非主線程的Handler而且發送消息、處理消息,這一系列的操做咱們應該怎麼辦那???不怎麼辦、涼拌~~~什麼意思???依葫蘆畫瓢,依然遵循上面的三步走,直接上代碼!!!!spa

public class ChildThreadHandlerActivity extends Activity {
    private MyThread childThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);

        childThread = new MyThread();
        childThread.start();

        Handler childHandler = new Handler(childThread.childLooper){//這樣以後,childHandler和childLooper就關聯起來了。
            public void handleMessage(Message msg) {
                
            };
        };
    }

    private class MyThread extends Thread{
        public Looper childLooper;

        @Override
        public void run() {
            Looper.prepare();//建立與當前線程相關的Looper
            childLooper = Looper.myLooper();//獲取當前線程的Looper對象
            Looper.loop();//調用此方法,消息纔會循環處理
        }
    }
}

代碼如上,咱們依然循序Android的三步走戰略,完成了子線程Handler的建立,難道這樣建立完了,就能夠發消息了麼?發的消息在什麼線程處理?一系列的問題,怎麼辦?看代碼!!!運行上述代碼,咱們發現一個問題,就是此代碼一會崩潰、一會不崩潰,經過查看日誌咱們看到崩潰的緣由是空指針。誰爲空???查到是咱們的Looper對象,怎麼會那?我不是在子線程的run方法中初始化Looper對象了麼?話是沒錯,可是你要知道,當你statr子線程的時候,雖然子線程的run方法獲得執行,可是主線程中代碼依然會向下執行,形成空指針的緣由是當咱們new Handler(childThread.childLooper)的時候,run方法中的Looper對象還沒初始化。固然這種狀況是隨機的,因此形成偶現的崩潰。線程

  那怎麼辦?難道咱們不能建立子線程Handler ???No!!!No!!!No!!!,你能想到的Android早就爲咱們實現好了,HandlerThread類就是解決這個問題的關鍵所在,看代碼!!!指針

public class HandlerThreadActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
        TextView textView = (TextView) findViewById(R.id.tv);
        textView.setText("HandlerThreadActivity.class");

        HandlerThread handlerThread = new HandlerThread("HandlerThread");
        handlerThread.start();

        Handler mHandler = new Handler(handlerThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Log.d("HandlerThreadActivity.class","uiThread2------"+Thread.currentThread());//子線程
            }
        };

        Log.d("HandlerThreadActivity.class","uiThread1------"+Thread.currentThread());//主線程
        mHandler.sendEmptyMessage(1);
    }
}

建立HandlerThread對象的時候,有個參數,是指定線程名字的。上面的代碼無論運行多少次都不會奔潰!!!而且這種方法建立的handler的handleMessage方法運行在子線程中。因此咱們能夠在這裏處理一些耗時的邏輯。到此咱們完成了主線程給子線程發通知,在子線程作耗時邏輯的操做。日誌

  下面咱們去看看源碼,看看爲何使用HandlerThread就能夠避免空指針那?code

    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

HandlerThread類的getLooper方法如上,咱們看到當咱們獲取當前線程Looper對象的時候,會先判斷當前線程是否存活,而後還要判斷Looper對象是否爲空,都知足以後纔會返回給我Looper對象,不然處於等待狀態!!既然有等待,那就有喚醒的時候,在那裏那???咱們發現HandlerThread的run方法中,有以下代碼:

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

說明了什麼那???HandlerThread類start的時候,Looper對象就初始化了,並喚醒以前等待的。因此HandlerThread很好的避免了以前空指針的產生。因此之後要想建立非主線程的Handler時,咱們用HandlerThread類提供的Looper對象便可。

  至此,前三篇咱們講了Handler的使用、工做原理、建立子線程Handler。下一篇我會講使用Handler引發的內存泄漏的解決辦法。

相關文章
相關標籤/搜索