Android App在線(xiàn)程中創(chuàng)建handler的方法講解
相關(guān)概念
1.Handler:可以看做是一個(gè)工具類(lèi),用來(lái)向消息隊(duì)列中插入消息的;
2.Thread:所有與Handler相關(guān)的功能都是與Thread密不可分的,Handler會(huì)與創(chuàng)建時(shí)所在的線(xiàn)程綁定;
3.Message:消息;
4.MessageQueue:消息隊(duì)列,對(duì)消息進(jìn)行管理,實(shí)現(xiàn)了一個(gè)Message鏈表;
5.Looper:消息循環(huán),從MessageQueue中取出Message進(jìn)行處理;
6.HandlerThread:繼承Thread,實(shí)例化時(shí)自動(dòng)創(chuàng)建Looper對(duì)象,實(shí)現(xiàn)一個(gè)消息循環(huán)線(xiàn)程.
在Android開(kāi)發(fā)中經(jīng)常會(huì)使用到線(xiàn)程,一想到線(xiàn)程,一般都會(huì)想到:
new Thread(){...}.start();
這樣的方式。這樣如果在一個(gè)Activity中多次調(diào)用上面的代碼,那么將創(chuàng)建多個(gè)匿名線(xiàn)程,如果這些線(xiàn)程的沒(méi)有被銷(xiāo)毀,那肯定會(huì)影響性能呢。這個(gè)時(shí)候我么就想到了android提供的一個(gè)異步處理線(xiàn)程的類(lèi)HandlerThread。
一般Handler的用法
Handler handler = new Handler(){...};
這樣創(chuàng)建的handler是在主線(xiàn)程即UI線(xiàn)程下的Handler,即這個(gè)Handler是與UI線(xiàn)程下的默認(rèn)Looper綁定的(當(dāng)然也只有主線(xiàn)程才能這么干,子線(xiàn)程是干不了的,除非自己創(chuàng)建個(gè)looper)。因此,有些時(shí)候會(huì)占用ui主線(xiàn)程,引起一些問(wèn)題,所以我們就想到了重新創(chuàng)建個(gè)子線(xiàn)程,來(lái)處理handler。。。。
使用HandlerThread解決問(wèn)題
HandlerThread實(shí)際上繼承于Thread,只不過(guò)它比普通的Thread多了一個(gè)Looper。我們可以使用下面的例子創(chuàng)建Handler
HandlerThread thread = new HandlerThread("MyHandlerThread");
thread.start();
創(chuàng)建HandlerThread時(shí)要把它啟動(dòng)了,即調(diào)用start()方法。
接著就是handler的使用,如下:
mHandler = new Handler(thread.getLooper()); //TODO:you can post or send something....
創(chuàng)建Handler時(shí)將HandlerThread中的looper對(duì)象傳入。那么這個(gè)mHandler對(duì)象就是與HandlerThread這個(gè)線(xiàn)程綁定了(這時(shí)就不再是與UI線(xiàn)程綁定了,這樣它處理耗時(shí)操作將不會(huì)阻塞UI)。
線(xiàn)程中消息處理的流程圖

消息插入隊(duì)列的位置由參數(shù)uptimeMillis來(lái)確定。
Handler與線(xiàn)程的關(guān)系

1.HandlerThread就是一個(gè)封裝了Looper的Thread.
2.Handler會(huì)與實(shí)例化時(shí)所在的線(xiàn)程綁定.
UI線(xiàn)程與子線(xiàn)程通信相關(guān)

1.需要更新UI,則需要使用與主線(xiàn)程綁定的Handler發(fā)送消息,若使用在子線(xiàn)程中創(chuàng)建的Handler則會(huì)拋出異常;
2.子線(xiàn)程中實(shí)例化Handler對(duì)象首先需要調(diào)用Looper.prepare(),否則會(huì)拋出異常;
3.調(diào)用Looper.loop()方法消息循環(huán)才會(huì)啟動(dòng);
使用Handler時(shí)一些需要注意的地方
Looper.prepare(),主線(xiàn)程使用handler,系統(tǒng)默認(rèn)prepare了,子線(xiàn)程中創(chuàng)建handler必須在前面Looper.prepare(),后面加上Looper.loop();
源碼中:
主線(xiàn)程:
在程序啟動(dòng)的時(shí)候,系統(tǒng)已經(jīng)幫我們自動(dòng)調(diào)用了Looper.prepare()方法。查看ActivityThread中的main()
public static void main(String[] args) {
SamplingProfilerIntegration.start();
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
EventLogger.setReporter(new EventLoggingReporter());
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
請(qǐng)注意Looper.prepareMainLooper():
public static final void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
if (Process.supportsProcesses()) {
myLooper().mQueue.mQuitAllowed = false;
}
}
子線(xiàn)程:
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare()
handler2 = new Handler();
Looper.loop()
}
}).start();
如果沒(méi)有Looper.prepare().會(huì)報(bào)錯(cuò):
Can't create handler inside thread that has not called Looper.prepare()
因?yàn)闆](méi)looper對(duì)象創(chuàng)建
looper.prepare()源碼:
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
相關(guān)文章
Android 基礎(chǔ)入門(mén)教程——開(kāi)發(fā)環(huán)境搭建
這篇文章主要介紹了Android 如何搭建開(kāi)發(fā)環(huán)境,文中講解非常細(xì)致,幫助大家開(kāi)始學(xué)習(xí)Android,想要學(xué)習(xí)Android的朋友可以了解下2020-06-06
Android中PopupWindow彈出式窗口使用方法詳解
這篇文章主要為大家詳細(xì)介紹了Android中PopupWindow彈出式窗口的使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-09-09
recycleview實(shí)現(xiàn)拼多多首頁(yè)水平滑動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了recycleview實(shí)現(xiàn)拼多多首頁(yè)水平滑動(dòng)效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05
Android實(shí)現(xiàn)簡(jiǎn)單的文件下載與上傳
今天小編就為大家分享一篇關(guān)于Android實(shí)現(xiàn)簡(jiǎn)單的文件下載與上傳,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12
android 捕獲系統(tǒng)異常并上傳日志具體實(shí)現(xiàn)
這篇文章介紹了android 捕獲系統(tǒng)異常并上傳日志具體實(shí)現(xiàn),有需要的朋友可以參考一下2013-09-09
Android自定義控件RatingBar調(diào)整字體大小
這篇文章主要為大家詳細(xì)介紹了Android自定義控件RatingBar調(diào)整字體大小的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
RecyclerView Adapter輔助類(lèi)詳解及示例代碼
本文主要介紹RecyclerView Adapter輔助類(lèi)的知識(shí),這里整理了詳細(xì)資料及簡(jiǎn)單示例代碼,幫助大家學(xué)習(xí)這部分的內(nèi)容,有興趣的小伙伴可以參考下2016-09-09
Android 中使用ContentObserver模式獲取短信用正則自動(dòng)填充驗(yàn)證碼
這篇文章主要介紹了Android 中使用ContentObserver模式獲取短信用正則自動(dòng)填充驗(yàn)證碼,首先使用了ContentObserver監(jiān)聽(tīng)短信,然后從短信中用正則的分組去拿到驗(yàn)證碼,具體實(shí)現(xiàn)代碼大家參考下本文2017-02-02
Android 實(shí)時(shí)監(jiān)測(cè)(監(jiān)聽(tīng))網(wǎng)絡(luò)連接狀態(tài)變化
這篇文章主要介紹了Android 實(shí)時(shí)監(jiān)測(cè)(監(jiān)聽(tīng))網(wǎng)絡(luò)連接狀態(tài)變化的相關(guān)知識(shí),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-06-06
android 仿微信demo——注冊(cè)功能實(shí)現(xiàn)(移動(dòng)端)
本篇文章主要介紹了微信小程序-閱讀小程序?qū)嵗╠emo),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望能給你們提供幫助2021-06-06

