Android App在線程中創(chuàng)建handler的方法講解
相關(guān)概念
1.Handler:可以看做是一個(gè)工具類(lèi),用來(lái)向消息隊(duì)列中插入消息的;
2.Thread:所有與Handler相關(guān)的功能都是與Thread密不可分的,Handler會(huì)與創(chuàng)建時(shí)所在的線程綁定;
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)線程.
在Android開(kāi)發(fā)中經(jīng)常會(huì)使用到線程,一想到線程,一般都會(huì)想到:
new Thread(){...}.start();
這樣的方式。這樣如果在一個(gè)Activity中多次調(diào)用上面的代碼,那么將創(chuàng)建多個(gè)匿名線程,如果這些線程的沒(méi)有被銷(xiāo)毀,那肯定會(huì)影響性能呢。這個(gè)時(shí)候我么就想到了android提供的一個(gè)異步處理線程的類(lèi)HandlerThread。
一般Handler的用法
Handler handler = new Handler(){...};
這樣創(chuàng)建的handler是在主線程即UI線程下的Handler,即這個(gè)Handler是與UI線程下的默認(rèn)Looper綁定的(當(dāng)然也只有主線程才能這么干,子線程是干不了的,除非自己創(chuàng)建個(gè)looper)。因此,有些時(shí)候會(huì)占用ui主線程,引起一些問(wèn)題,所以我們就想到了重新創(chuàng)建個(gè)子線程,來(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è)線程綁定了(這時(shí)就不再是與UI線程綁定了,這樣它處理耗時(shí)操作將不會(huì)阻塞UI)。
線程中消息處理的流程圖
消息插入隊(duì)列的位置由參數(shù)uptimeMillis來(lái)確定。
Handler與線程的關(guān)系
1.HandlerThread就是一個(gè)封裝了Looper的Thread.
2.Handler會(huì)與實(shí)例化時(shí)所在的線程綁定.
UI線程與子線程通信相關(guān)
1.需要更新UI,則需要使用與主線程綁定的Handler發(fā)送消息,若使用在子線程中創(chuàng)建的Handler則會(huì)拋出異常;
2.子線程中實(shí)例化Handler對(duì)象首先需要調(diào)用Looper.prepare(),否則會(huì)拋出異常;
3.調(diào)用Looper.loop()方法消息循環(huán)才會(huì)啟動(dòng);
使用Handler時(shí)一些需要注意的地方
Looper.prepare(),主線程使用handler,系統(tǒng)默認(rèn)prepare了,子線程中創(chuàng)建handler必須在前面Looper.prepare(),后面加上Looper.loop();
源碼中:
主線程:
在程序啟動(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; } }
子線程:
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使用SharedPreferences存儲(chǔ)XML文件的實(shí)現(xiàn)方法
這篇文章主要介紹了Android使用SharedPreferences存儲(chǔ)XML文件的實(shí)現(xiàn)方法,實(shí)例分析了SharedPreferences類(lèi)的基本初始化與文件存儲(chǔ)相關(guān)技巧,需要的朋友可以參考下2016-07-07Android ApplicationInfo 應(yīng)用程序信息的詳解
這篇文章主要介紹了Android ApplicationInfo 應(yīng)用程序信息的詳解的相關(guān)資料,希望通過(guò)本文能幫助到大家,需要的朋友可以參考下2017-10-10Android自定義View實(shí)現(xiàn)QQ運(yùn)動(dòng)積分轉(zhuǎn)盤(pán)抽獎(jiǎng)功能
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)QQ運(yùn)動(dòng)積分轉(zhuǎn)盤(pán)抽獎(jiǎng)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10Emoji表情在Android JNI中的兼容性問(wèn)題詳解
這篇文章主要給大家介紹了關(guān)于Emoji表情在Android JNI中的兼容性問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Android JNI具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09android Setting中隱藏項(xiàng)實(shí)現(xiàn)原理與代碼
我們都知道做程序員有時(shí)會(huì)惡搞,就像android中,程序員在setting中就隱藏這樣一項(xiàng),接下來(lái)將詳細(xì)介紹,感興趣的朋友可以了解下哦2013-01-01Android實(shí)現(xiàn)多維商品屬性SKU選擇
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)多維商品屬性SKU選擇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-10-10淺析Android手機(jī)衛(wèi)士手機(jī)定位的原理
手機(jī)定位的三種方式:網(wǎng)絡(luò)定位,基站定位,GPS定位。本文給大家介紹Android手機(jī)衛(wèi)士手機(jī)定位的原理,感興趣的朋友一起學(xué)習(xí)吧2016-04-04Android UI 之實(shí)現(xiàn)多級(jí)樹(shù)形列表TreeView示例
這篇文章主要介紹了Android UI 之實(shí)現(xiàn)多級(jí)列表TreeView示例,TreeView就是在Windows中常見(jiàn)的多級(jí)列表樹(shù),有興趣的可以了解一下。2017-03-03