Android 中的 HandlerThread 詳解
HandlerThread是Android API提供的一個便捷的類,使用它我們可以快速的建立一個帶有Looper的執行緒,有了Looper這個執行緒,我們又可以生成Handler,那麼 HandlerThread是什麼,可以做什麼呢,有哪些奇技淫巧可以被我們利用呢?
實現原理
在介紹原理之前,我們先使用普通的Thread來建立一個Handler,建立的過程大致如下:
Handler mHandler; private void createManualThreadWithHandler() { new Thread() { @Override public void run() { super.run(); Looper.prepare(); mHandler = new Handler(Looper.myLooper()); Looper.loop(); } }.start(); }
實現很簡單,在目標執行緒內如下配置
- 呼叫Looper.prepare 建立與當前執行緒繫結的Looper例項
- 使用上面建立的Looper生成Handler例項
- 呼叫Looper.loop()實現訊息迴圈
明白上面的實現步驟,HandlerThread的實現也就簡單了,其實現為:
@Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }
確實很簡單,無需贅述。
Handler原理
要理解Handler的原理,理解如下幾個概念即可茅塞頓開。
- Message 意為訊息,傳送到Handler進行處理的物件,攜帶描述資訊和任意資料。
- MessageQueue 意為訊息佇列,Message的集合。
- Looper 有著一個很難聽的中文名字,訊息泵,用來從MessageQueue中抽取Message,傳送給Handler進行處理。
- Handler 處理Looper抽取出來的Message。
如何使用
HandlerThread使用起來很容易,首先需要進行初始化。
private Handler mHandler; private LightTaskManager() { HandlerThread workerThread = new HandlerThread("LightTaskThread"); workerThread.start(); mHandler = new Handler(workerThread.getLooper()); }
注意:上面的workerThread.start();必須要執行。
至於如何使用HandlerThread來執行任務,主要是呼叫Handler的API
- 使用post方法提交任務,postAtFrontOfQueue將任務加入到佇列前端,postAtTime指定時間提交任務,postDelayed延後提交任務。
- 使用sendMessage方法可以傳送訊息,sendMessageAtFrontOfQueue將該訊息放入訊息佇列前端,sendMessageAtTime 指定時間傳送訊息,sendMessageDelayed延後提交訊息。
通過包裹Handler API,我們可以實現如下程式碼(僅post相關方法):
public void post(Runnable run) { mHandler.post(run); } public void postAtFrontOfQueue(Runnable runnable) { mHandler.postAtFrontOfQueue(runnable); } public void postDelayed(Runnable runnable, long delay) { mHandler.postDelayed(runnable, delay); } public void postAtTime(Runnable runnable, long time) { mHandler.postAtTime(runnable, time); }
控制優先順序
瞭解到如何使用之外,關於HandlerThread的使用需要上升一個界別,那就是優化。這裡的優化主要是合理調整HandlerThread的優先順序。
HandlerThread的預設優先順序是Process.THREAD_PRIORITY_DEFAULT,具體值為0。執行緒的優先順序的取值範圍為-20到19。優先順序高的獲得的CPU資源更多,反之則越少。-20代表優先順序最高,19最低。0位於中間位置,但是作為工作執行緒的HandlerThread沒有必要設定這麼高的優先順序,因而需要我們降低其優先順序。
可控制的優先順序
- THREAD_PRIORITY_DEFAULT,預設的執行緒優先順序,值為0。
- THREAD_PRIORITY_LOWEST,最低的執行緒級別,值為19。
- THREAD_PRIORITY_BACKGROUND 後臺執行緒建議設定這個優先順序,值為10。
- THREAD_PRIORITY_MORE_FAVORABLE 相對THREAD_PRIORITY_DEFAULT稍微優先,值為-1。
- THREAD_PRIORITY_LESS_FAVORABLE 相對THREAD_PRIORITY_DEFAULT稍微落後一些,值為1。
以上的這些優先順序都是可以在程式中設定的,除此之外還有不可控的優先順序均有系統進行自動調整。
如何修改許可權
最通用的就是在run方法中,加入合理的設定優先順序程式碼,比如
Runnable run = new Runnable() { @Override public void run() { android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } }; LightTaskManager.getInstance().post(run);
上述方法不僅適用於HandlerThread,也可以適用於其他的執行緒。
除此之外,HandlerThread的構造方法也提供了設定優先順序的功能。用法如下:
HandlerThread workerThread = new HandlerThread("LightTaskThread", Process.THREAD_PRIORITY_BACKGROUND);
關於設定優先順序,系統的AsyncTask已經開始進行了預設設定,將執行緒的優先順序設定成THREAD_PRIORITY_BACKGROUND了。
public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //noinspection unchecked Result result = doInBackground(mParams); Binder.flushPendingCommands(); return postResult(result); } }; }
關於Android中執行緒的排程詳情,請參考 剖析Android中程式與執行緒排程之nice
應用場景
我們可以使用HandlerThread處理本地IO讀寫操作(資料庫,檔案),因為本地IO操作大多數的耗時屬於毫秒級別,對於單執行緒 + 非同步佇列的形式 不會產生較大的阻塞。因此在這個HandlerThread中不適合加入網路IO操作。
對於本地IO讀取操作,我們可以使用postAtFrontOfQueue方法,快速將讀取操作加入佇列前端執行,必要時返回給主執行緒更新 UI。示例場景,從資料庫中讀取資料展現在ListView中。注意讀取也是需要花費一定時間,推薦在資料展示之前有必要的使用者可感知進度提示。
對於本地IO寫操作,根據具體情況,選擇post或者postDelayed方法執行。比如SharedPreference commit,或者檔案寫入操作。
相關文章
- 終止Android中HandlerThread的方法Androidthread
- Android中HandlerThread的使用及原始碼解析Androidthread原始碼
- Android中的onWindowFocusChanged()方法詳解Android
- 詳解Android中AsyncTask的使用Android
- Android中的ANR用法詳解Android
- Android中的Context詳解AndroidContext
- Android 中的 Checkbox 詳解Android
- Android HandlerThread使用總結Androidthread
- Android中文API(128) —— HandlerThreadAndroidAPIthread
- Android中PopupWindow使用詳解Android
- Android中AsyncTask使用詳解Android
- Android中Activity的LunchMode引數詳解Android
- Android中SQLite應用詳解AndroidSQLite
- Android中Context用法詳解AndroidContext
- Android 中 HttpURLConnection 使用詳解AndroidHTTP
- Android中HttpURLConnection使用詳解AndroidHTTP
- 詳解Android中的四大元件之一:Activity詳解Android元件
- Android開發中的MVP架構詳解AndroidMVP架構
- Android後臺任務(HandlerThread、AsyncTask、IntentService)AndroidthreadIntent
- Android 中 XML 資料解析詳解AndroidXML
- Android中App安裝位置詳解AndroidAPP
- Android逆向之旅---Android中的sharedUserId屬性詳解Android
- 詳解 Android 中的 IPC 機制:基礎篇Android
- Android中圖片的三層快取詳解Android快取
- 詳解在Android中整合高德定位功能Android
- Android中visibility屬性詳解Android
- android中View.measure方法詳解AndroidView
- Android中點選事件的四種寫法詳解Android事件
- Android中的Style、Theme詳解以及發展史Android
- Android中Handler Runnable與Thread的區別詳解Androidthread
- Android中的幾種網路請求方式詳解Android
- 詳解Android RxJava的使用AndroidRxJava
- IntentService 和 HandlerThread 的原理Intentthread
- Android應用中Clean架構使用詳解Android架構
- JavaScript中的this詳解JavaScript
- 詳解JavaScript中的thisJavaScript
- Visual Studio中的Android模擬器使用詳解Android
- Android AsyncTask 詳解Android