九、HandlerThread解析

Android系統(tǒng)中,執(zhí)行耗時(shí)操作都需要另外開(kāi)啟子線程來(lái)執(zhí)行,執(zhí)行完線程以后自動(dòng)銷(xiāo)毀。為了避免重復(fù)的創(chuàng)建和銷(xiāo)毀線程,避免過(guò)多的消耗性能,可以采用:

  • 1.使用線程池
  • 2.使用HandlerThread

1.HandleThread 使用場(chǎng)景,以及如何使用

使用場(chǎng)景

HandlerThread是Google幫我們封裝好的,可以用來(lái)執(zhí)行多個(gè)耗時(shí)操作,而不需要多次創(chuàng)建銷(xiāo)毀線程,里面是采用HandlerLooper實(shí)現(xiàn)的。

使用方式
  1. 創(chuàng)建HandlerThread的實(shí)例對(duì)象
      //構(gòu)造方法的參數(shù)表示的是線程的名稱(chēng)
  HandlerThread  mHandlerThread = new HandlerThread("wyw");
  1. 啟動(dòng)創(chuàng)建的實(shí)例對(duì)象
  mHandlerThread.start()
  1. 將實(shí)例對(duì)象和handler綁定在一起。(必須按照這三步進(jìn)行)
  mThreadHandler = new Handler(mHandlerThread.getLooper()) {
            @Override
            public void handleMessage(@NonNull Message msg) {
                checkForUpdate();
                if (isUpdate) {
                    mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
                }
            }
        };

完整使用實(shí)例代碼:

public class MyActivity extends AppCompatActivity {
    private static final int MSG_UPDATE_INFO = 0x100;

    private HandlerThread mHandlerThread;
    private Handler mThreadHandler;
    Handler mMainHandler = new Handler();
    private TextView tv;
    private boolean isUpdate = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //創(chuàng)建handlerThread實(shí)例
        mHandlerThread = new HandlerThread("wyw");
        //啟動(dòng)handlerThread實(shí)例
        mHandlerThread.start();
        //handlerThread 綁定handler
        mThreadHandler = new Handler(mHandlerThread.getLooper()) {
            @Override
            public void handleMessage(@NonNull Message msg) {
                checkForUpdate();
                if (isUpdate) {
                    mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
                }
            }
        };
    }

    private void checkForUpdate() {
        try {
            //模擬耗時(shí)
            Thread.sleep(1200);
            mMainHandler.post(new Runnable() {
                @Override
                public void run() {
                    String result = "實(shí)時(shí)更新中, 當(dāng)前股票行情: <fontcolor='red'>%d</font>";
                    result = String.format(result, (int) Math.random() * 5000 + 1000);
                    tv.setText(result);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        isUpdate = true;
        mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
    }

    @Override
    protected void onPause() {
        super.onPause();
        isUpdate = false;
        mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandlerThread.quit();
        mMainHandler.removeCallbacksAndMessages(null);
    }
}

2.HandlerThread源碼解析

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
//持有鎖機(jī)制來(lái)獲得當(dāng)前線程的Looper對(duì)象
        synchronized (this) {
            mLooper = Looper.myLooper();
//發(fā)出通知,當(dāng)前線程已經(jīng)創(chuàng)建mLooper對(duì)象成功,這里主要是通知getLooper方法中的waiter
            notifyAll();
        }
//線程的優(yōu)先級(jí)設(shè)置
        Process.setThreadPriority(mPriority);
//方法空實(shí)現(xiàn),可以重寫(xiě)這個(gè)方法,處理線程開(kāi)啟之前的準(zhǔn)備工作
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
 
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
//直到線程創(chuàng)建完Looper之后才能獲取Looper對(duì)象,Looper未創(chuàng)建成功阻塞
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }

    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    public int getThreadId() {
        return mTid;
    }
}
  • HandlerThread構(gòu)造方法,一個(gè)參數(shù)和兩個(gè)參數(shù)的,name代表當(dāng)前線程的名稱(chēng),priority代表線程的優(yōu)先級(jí)。
  • 前面強(qiáng)調(diào)在使用HandlerThread的時(shí)候必須先調(diào)用start(),接著才可以將HandlerThreadHandler綁定在一起。因?yàn)樵趓un()方法中,我們才初始化looper,而我們調(diào)用HandlerThread的start()方法的時(shí)候,線程會(huì)交給虛擬機(jī)調(diào)度,由虛擬機(jī)自動(dòng)調(diào)用run()方法。
  • run()方法中使用鎖機(jī)制和notifyAll()的原因,可以在getLooper()方法中找到。
    在獲取mLooper對(duì)象的時(shí)候存在一個(gè)同步的問(wèn)題,只有當(dāng)當(dāng)線程成功創(chuàng)建并且Looper對(duì)象也創(chuàng)建成功之后才能獲取mLooper的值。這里等待waite()和run()中的notifAll()共同實(shí)現(xiàn)同步。
  • quit()和quitSafe()的區(qū)別:
    通過(guò)源碼追蹤,可以發(fā)現(xiàn),實(shí)際這個(gè)兩個(gè)方法最終調(diào)用的是MessageQueue.quit(boolean safe)。MessageQueue.quit方法源碼:
    void quit(boolean safe) {
         if (!mQuitAllowed) {
             throw new IllegalStateException("Main thread not allowed to quit.");
         }
         synchronized (this) {
             if (mQuitting) {
                 return;
             }
             mQuitting = true;
             if (safe) {
                 removeAllFutureMessagesLocked();
             } else {
                 removeAllMessagesLocked();
             }
             // We can assume mPtr != 0 because mQuitting was previously false.
             nativeWake(mPtr);
         }
     }
    
    可以看出,這個(gè)方法根據(jù)傳入的參數(shù)safe來(lái)判斷執(zhí)行removeAllFutureMessagesLocked()或removeAllMessagesLocked()。
     private void removeAllMessagesLocked() {
         Message p = mMessages;
         while (p != null) {
             Message n = p.next;
             p.recycleUnchecked();
             p = n;
         }
         mMessages = null;
     }
    
    如果不是安全退出,執(zhí)行removeAllMessagesLocked(),該方法就是遍歷Message鏈表,移除所有信息的回調(diào),并重置為null。
     private void removeAllFutureMessagesLocked() {
         final long now = SystemClock.uptimeMillis();
         Message p = mMessages;
         if (p != null) {
             if (p.when > now) {
                 removeAllMessagesLocked();
             } else {
                 Message n;
                 for (;;) {
                     n = p.next;
                     if (n == null) {
                         return;
                     }
                     if (n.when > now) {
                         break;
                     }
                     p = n;
                 }
                 p.next = null;
                 do {
                     p = n;
                     n = p.next;
                     p.recycleUnchecked();
                 } while (n != null);
             }
         }
     }
    
    如果是安全的退出,執(zhí)行removeAllFutureMessagesLocked(),該方法,根據(jù)Message.when這個(gè)屬性,判斷我們當(dāng)前消息隊(duì)列是否正在處理消息,沒(méi)有處理消息的話,直接移除所有的回調(diào),正在處理的話,等待該消息處理完畢再退出該循環(huán)。因此說(shuō)quiteSafe()是安全的,而quit()是不安全的,因?yàn)閝uit()不管是否正在處理,直接移除所有的回調(diào)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容