Android HandlerThread的使用及原理詳解
一、HandlerThread的含義
HandlerThread能夠新建擁有Looper的線程。這個(gè)Looper能夠用來新建其他的Handler。(線程中的Looper)需要注意的是,新建的時(shí)候需要被回調(diào)。
二、HandlerThread的用法
一般情況下,我們會(huì)經(jīng)常用Handler在子線程中更新UI線程,那是因?yàn)樵谥骶€程中有Looper循環(huán),而HandlerThread新建擁有Looper的子線程又有什么用呢?
必然是執(zhí)行耗時(shí)操作。舉個(gè)例子,數(shù)據(jù)實(shí)時(shí)更新,我們每10秒需要切換一下顯示的數(shù)據(jù),如果我們將這種長時(shí)間的反復(fù)調(diào)用操作放到UI線程中,雖說可以執(zhí)行,但是這樣的操作多了之后,很容易會(huì)讓UI線程卡頓甚至崩潰。
于是,就必須在子線程中調(diào)用這些了。
HandlerThread繼承自Thread,一般適應(yīng)的場景,便是集Thread和Handler之所長,適用于會(huì)長時(shí)間在后臺(tái)運(yùn)行,并且間隔時(shí)間內(nèi)(或適當(dāng)情況下)會(huì)調(diào)用的情況,比如上面所說的實(shí)時(shí)更新。
三、實(shí)現(xiàn)每2秒更新一下UI
public class MainActivity extends AppCompatActivity {
private TextView tvMain;
private HandlerThread mHandlerThread;
//子線程中的handler
private Handler mThreadHandler;
//UI線程中的handler
private Handler mMainHandler = new Handler();
//以防退出界面后Handler還在執(zhí)行
private boolean isUpdateInfo;
//用以表示該handler的常熟
private static final int MSG_UPDATE_INFO = 0x110;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvMain = (TextView) findViewById(R.id.tv_main);
initThread();
}
private void initThread()
{
mHandlerThread = new HandlerThread("check-message-coming");
mHandlerThread.start();
mThreadHandler = new Handler(mHandlerThread.getLooper())
{
@Override
public void handleMessage(Message msg)
{
update();//模擬數(shù)據(jù)更新
if (isUpdateInfo)
mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
}
};
}
private void update()
{
try
{
//模擬耗時(shí)
Thread.sleep(2000);
mMainHandler.post(new Runnable()
{
@Override
public void run()
{
String result = "每隔2秒更新一下數(shù)據(jù):";
result += Math.random();
tvMain.setText(result);
}
});
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
@Override
protected void onResume()
{
super.onResume();
//開始查詢
isUpdateInfo = true;
mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
}
@Override
protected void onPause()
{
super.onPause();
//停止查詢
//以防退出界面后Handler還在執(zhí)行
isUpdateInfo = false;
mThreadHandler.removeMessages(MSG_UPDATE_INFO);
}
@Override
protected void onDestroy()
{
super.onDestroy();
//釋放資源
mHandlerThread.quit();
}
}
四、HandlerThread 原理
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
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();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
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;
}
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繼承自Thread,因此在run()中的邏輯都是在子線程中運(yùn)行的。
接下來就是兩個(gè)關(guān)鍵的方法,run()和getLooper():
run()中可以看到是很簡單的創(chuàng)建Looper以及讓Looper工作的邏輯。
run()里面當(dāng)mLooper創(chuàng)建完成后有個(gè)notifyAll(),getLooper()中有個(gè)wait(),這有什么用呢?因?yàn)榈膍Looper在一個(gè)線程中執(zhí)行創(chuàng)建,而我們的handler是在UI線程中調(diào)用getLooper()初始化的。
也就是說,我們必須等到mLooper創(chuàng)建完成,才能正確的返回。getLooper();wait(),notify()就是為了解決這兩個(gè)線程的同步問題。
相關(guān)文章
Android Service中使用Toast無法正常顯示問題的解決方法
這篇文章主要介紹了Android Service中使用Toast無法正常顯示問題的解決方法,分析了Service中Toast無法正常顯示的原因與相關(guān)的解決方法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-10-10
android studio 3.0 升級(jí) 項(xiàng)目遇到的問題及更改思路(問題小結(jié))
Android Studio從3.0版本新增了許多功能,當(dāng)然首當(dāng)其沖就是從3.0版本新增了對(duì) Kotlin 開發(fā)語言的支持,除此之外還有其他一些新功能。很多小伙伴在android studio 3.0 升級(jí)項(xiàng)目遇到很多問題,下面小編給大家分享一些問題小結(jié)及解決辦法,一起看看吧2017-11-11
ComposeDesktop開發(fā)桌面端多功能APK工具
這篇文章主要為大家介紹了ComposeDesktop開發(fā)桌面端多功能APK工具實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
TextView長按復(fù)制的實(shí)現(xiàn)方法(總結(jié))
下面小編就為大家?guī)硪黄猅extView長按復(fù)制的實(shí)現(xiàn)方法(總結(jié))。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04
android實(shí)現(xiàn)http中請求訪問添加cookie的方法
這篇文章主要介紹了android實(shí)現(xiàn)http中請求訪問添加cookie的方法,實(shí)例分析了兩種添加cookie的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10
Android中將一個(gè)圖片切割成多個(gè)圖片的實(shí)現(xiàn)方法
有種場景,我們想將一個(gè)圖片切割成多個(gè)圖片。比如我們在開發(fā)一個(gè)拼圖的游戲,就首先要對(duì)圖片進(jìn)行切割2013-05-05
Android實(shí)現(xiàn)webview實(shí)例代碼
本篇文章主要介紹了Android實(shí)現(xiàn)webview實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06
Android仿網(wǎng)易嚴(yán)選底部彈出菜單效果
這篇文章主要為大家詳細(xì)介紹了Android仿網(wǎng)易嚴(yán)選底部彈出菜單效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07

