Android開發:HandlerThread是什麼?

2021-03-02 享學課堂online

這道題想考察什麼?

是否了解HandlerThread的使用?

是否了解HandlerThread的原理?

考察的知識點

HandlerThread的使用

HandlerThread的原理

考生應該如何回答

1、首先,我們可以圍繞HandlerThread是什麼,什麼場景下會用HandlerThread,HandlerThread怎麼用這幾個話題來概述一下。

只要有過Android開發經驗的同學都知道,在Android中,執行耗時任務的場景特別常見,比如圖片資源的下載、資料庫的增刪改查、文件IO等。為了保證APP的流暢性,這些耗時操作一般都需要放入子線程處理。這裡做法就比較多了,也是體現程式設計師級別的地方。最簡單粗暴的方法就是每次new出一個Thread去執行耗時任務,執行完任務這個線程也就銷毀了,這種做法是最不應當採取的,消耗太大。

第二種普遍的做法就是使用線程池,耗時任務來了直接丟到線程池處理,但線程池整體量級有些偏重,在項目中維持一個性能較優的線程池並非易事,它需要根據項目實際情況去調整線程池的各種參數。介於這兩者之間,Google工程師又貼心的為我們提供了一個輕量級的HandlerThread,可以用來執行多個耗時操作,而不需要多次開啟、關閉線程,內部是將Thread和Handler進行封裝實現。話不多說,直接上代碼,使用HandlerThread來執行耗時任務,看看是否優雅。

// 定義異步任務消息private final int MSG_EXECUTE_TASK = 100;
/** * 創建HandlerThread */private void initHandlerThread() { // 必須按照以下三個步驟: // 1、創建HandlerThread的實例對象 mHandlerThread = new HandlerThread("HandlerThread"); // 2、啟動我們創建的HandlerThread線程,要先start,為什麼?下面源碼會解釋 mHandlerThread.start(); // 3、將handlerThread與Handler綁定在一起。 mHandler = new Handler(mHandlerThread.getLooper()) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); // 接收到MSG_EXECUTE_TASK消息時,處理耗時任務 if (msg.what == MSG_EXECUTE_TASK) { try { Log.i(TAG, "執行耗時任務->thread:" + Thread.currentThread().getName()); //模擬耗時任務,當前線程睡3s Thread.sleep(3000); Log.i(TAG, "耗時任務執行結束->thread:" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } } };}
/** * 發送耗時任務消息 * @param view */public void doDBOperation(View view) { // 發送一次任務消息 mHandler.sendEmptyMessage(MSG_EXECUTE_TASK); // 10s後再發送一次任務消息 mHandler.sendEmptyMessageDelayed(MSG_EXECUTE_TASK, 10000);}

// logcat輸出如下,注意下面的時間戳// 2020-09-29 17:09:37.295 I/HandlerThreadActivity: 執行耗時任務 -> thread:HandlerThread// 2020-09-29 17:09:40.297 I/HandlerThreadActivity: 耗時任務執行結束 -> thread:HandlerThread// 2020-09-29 17:09:47.302 I/HandlerThreadActivity: 執行耗時任務 -> thread:HandlerThread// 2020-09-29 17:09:50.303 I/HandlerThreadActivity: 耗時任務執行結束 -> thread:HandlerThread

例子很簡單,執行兩次耗時3s的任務,中間相隔10s,從Logcat中列印的日誌可以看出,兩次耗時任務依次都執行在HandlerThread線程,並沒有去創建新線程,符合期望。怎麼樣,使用起來是不是感覺還可以,核心步驟就是將Thread與Handler綁定起來,接下來所有操作就跟我們平時大量使用的handler一模一樣了,即發送消息與處理消息。

另外還有一點需要注意,在HandlerThread不再使用的時候需要手動關閉,調用quit()或者quitSafe()方法。

if (mHandlerThread != null) {        mHandlerThread.quit();    mHandlerThread = null;}

2、知其然知其所以然。從事軟體開發的我們,絕不能僅僅停留在API使用層面,必須得進入源碼,一探究竟,看看HandlerThread內部到底幹了什麼,這裡有一點需要注意,看HandlerThread的源碼之前,你必須得先搞懂Handler哦,在分析過程中有關handler的機制不會贅述了。

public class HandlerThread extends Thread {    }

可以看出HandlerThread繼承自Thread,所以說最終也是一個線程,當調用start方法後,便會處於就緒狀態,等待CPU的調度。

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

HandlerThread的run方法其實就是創建了一個looper,然後通過looper去循環消息,等待消息的到來。到目前可以解釋上面代碼中留的一個問題了。

使用HandlerThread時,為什麼要先調用start方法?

因為在HandlerThread的run方法裡才會初始化Looper,所以如果不先讓子線程start起來,那麼下一步創建主線程的handler時,獲取looper肯定為空。

當然這裡有人肯定還有另外的疑問,上面的代碼中,出現了synchronized、notifyAll這些並發編程裡的概念,是做什麼的?不用懷疑,肯定有用處。

mHandler = new Handler(mHandlerThread.getLooper())

創建Handler時,傳入的looper參數是通過mHandlerThread.getLooper()獲取的。

public Looper getLooper() {        if (!isAlive()) {        return null;    }        synchronized (this) {                while (isAlive() && mLooper == null) {            try {                                wait();            } catch (InterruptedException e) {            }        }    }    return mLooper;}

可以看到,這裡是獲取Looper,與上面初始化Looper正好對應。因為mLooper在HandlerThread中執行,而我們的handler是在UI線程初始化的,也就是說,獲取looper的時候,looper有可能還沒創建好,所以通過線程的wait()與notify()的協作解決這兩個線程的同步問題。如果mLooper為null,並且線程alive的話,獲取線程會處於等待狀態,當初始化looper完成後,調用notifyAll喚醒等待線程,這樣便自動完成獲取操作了。

3、最後,總結一下,其實HandlerThread的源碼並不難,代碼量也不多,核心就是Looper的創建與獲取,只要能把上面的源碼吃透了,相信關於HandlerThread的問題肯定難不住聰明的你了。

相關焦點

  • Android Handler 由淺入深源碼全解析
    前言    Handler在android開發中可謂隨處可見,不論你是一個剛開始學習android
  • Android開發 面試必問的Handler消息機制
    = null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }這裡如果有疑問說ThreadLocal是什麼東西,其實ThreadLocal
  • Handler原理,這一篇就夠了
    使用方法package com.example.test.myapplication;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.widget.Toast
  • 重學 Android 之 Handler 機制
    ,handler 機制的使用幾乎隨處可見,作為面試中的常客,我們真的了解 handler 嗎?以下,是本文的整個思維導圖,相信通過這個閱讀會更加的清晰二、Handler 說明1、Handler 機制 是什麼?答:Handler 機制 即為 一套 Android 消息傳遞機制2、Handler有什麼用?
  • Android中Handler問題匯總【面試必備】
    3、handler中執行sendMessage或者post操作,這些操作執行的線程是handler中Looper所在的線程,和handler在哪裡創建沒關係,和Handler中的Looper在那創建有關係。
  • 面試必備:異步 Handler 十大必問!
    Looper.prepare 和 Looper.loop 都做了什麼事情呢?我們知道如果在子線程中直接創建一個 Handler 的話,會報如下的錯誤:"Can't create handler inside thread xxx that has not called Looper.prepare()我們可以看一下 Handler 的構造函數,裡面會對 Looper 進行判斷,如果通過 ThreadLocal
  • 5分鐘了解Handler錯誤使用場景
    其次回調handler構造函數中的callback。    最後回調handler handleMessage()。handler inside thread Thread[Thread-2,5,main] that has not called Looper.prepare()at android.os.Handler.
  • 【android開發】Android binder學習一:主要概念
    目前linux支持IPC包括傳統的管道,System V IPC,即消息隊列/共享內存/信號量,以及socket中只有socket支持Client-Server的通信方式。Android系統為開發者提供了豐富進程間通信的功能接口,媒體播放,傳感器,無線傳輸。這些功能都由不同的server來管理。開發都只關心將自己應用程式的client與server的通信建立起來便可以使用這個服務。
  • Android開發:AsyncTask的原理
    這道題想考察什麼?是否了解AsyncTask的使用是否研究過AsyncTask的源碼考察的知識點AsyncTask的使用AsyncTask的源碼解析AsyncTask的原理總結考生應該如何回答1、首先,我們需要對AsyncTask的基本認識以及使用進行解答。
  • Handler 使用詳解
    、主線程發送消息給子線程的例子八、子線程給主線程發送消息的方法九、 主、子 線程 互發消息方法十、子線程方法中調用主線程更新UI的方法十一、移除Handler 發送的消息方法一、Handler 簡介在了解Handler 之前,我們需要先了解Handler的繼承關係 繼承關係如下:java.lang.Object ↳ android.os.Handler
  • Android Handler原理詳解
    or leaks might occur: " +                klass.getCanonicalName());        }    }    mLooper = Looper.myLooper();    if (mLooper == null) {        throw new RuntimeException(            "Can't create handler
  • Android Systrace 基礎知識(9)-MainThread 和 RenderThread 解讀
    queueBuffer) , SurfaceFlinger 在 Vsync-SF 到了之後,將所有準備好的 Buffer 取出進行合成(這個流程在講 SurfaceFlinger 的時候會提到)上面這個流程在 Android 基於 Choreographer 的渲染機制詳解[13] 這篇文章裡面已經介紹的很詳細了,包括每一幀的 doFrame 都在做什麼
  • 我感覺我學了一個假的Android...
    在平時的Android開發中,如果一個新手遇到一個這樣的錯:android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
  • Android Camera2 實現高幀率預覽錄製(附源碼)
    :name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE
  • Android消息機制之Looper、Handler、MessageQueen
    MessageQueen源碼分析Handler源碼分析面試題結語前言Android消息機制可以說是我們Android工程師面試題中的必考題,弄懂它的原理是我們避不開的任務,所以長痛不如短痛,花點時間幹掉他,廢話不多說,開車啦Android消息機制的簡介在安卓開發中
  • 你真的了解Handler嗎
    ❝提到handler,大家都想到些什麼呢,切換線程?延時操作?那麼你是否了解「IdleHandler,同步屏障,死循環」的設計原理?以及由Handler機制衍生的「IntentService,BlockCanary」?
  • Android開發必備的「80」個開源庫
    wiki 周刊https://github.com/bboyfeiyu/android-tech-frontier/wiki值得閱讀的 Android 技術文章https://github.com/bboyfeiyu/Worth-Reading-the-Android-technical-articles整理一些比較好的 Android 開發教程
  • 好的Android開發習慣
    html(點擊尾部閱讀原文前往)https://www.zhihu.com/question/27227425/answer/35973793知乎問題:本人剛開始學習android開發,經過一段時間的學習感覺一些開發過程中的習慣也十分的重要,比如文件命名,代碼的備份,注釋等。
  • 使用Executors,ThreadPoolExecutor,創建線程池,源碼分析理解
    ();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize
  • Android多線程:手把手帶你深入Handler源碼分析(上)
    前言    在Android開發的多線程應用場景中,Handler機制