為什么需要多線程技術(shù)?我認(rèn)為是因?yàn)楫?dāng)執(zhí)行任務(wù)時(shí)救拉,若是遇到一個(gè)很耗時(shí)的任務(wù)彻采,且該任務(wù)不需要與主線程同步執(zhí)行時(shí)腐缤,就可以另外開辟一個(gè)新的線程去處理該任務(wù),主線程則跳過該任務(wù)肛响,去處理下一個(gè)任務(wù)岭粤,節(jié)約了時(shí)間。
Android中多線程有兩個(gè)原則:
1.主線程不能執(zhí)行網(wǎng)絡(luò)下載特笋、文件讀寫等耗時(shí)操作
2.子線程不能刷新UI
1.Handler
用來管理進(jìn)程間通信,維持著安卓app運(yùn)行的框架
Handler機(jī)制包括以下幾個(gè)類:Handler剃浇、Looper、MessageQueue、Message
- 1.Message虎囚,線程之間傳遞的消息角塑,用于不同線程之間的數(shù)據(jù)交互。
- 2.Handler淘讥,用于發(fā)送和處理消息圃伶。其中的sendMessage()用來發(fā)送消息,handleMessage()用于消息處理适揉。
- 3.MessageQueue留攒,消息隊(duì)列,用于存放Handler發(fā)送的消息嫉嘀,一個(gè)線程只有一個(gè)消息隊(duì)列炼邀,MessageQueue.enqueue()消息入隊(duì)。
- 4.Looper剪侮,可以理解為消息隊(duì)列的管理者拭宁,當(dāng)發(fā)現(xiàn)MessageQueue中存在消息,Looper就會(huì)將消息傳遞到handleMessage()方法中瓣俯,一個(gè)線程只有一個(gè)Looper杰标。
1.基本用法:
①:定義Handler并重寫handleMessage方法
(此處是規(guī)定了handler將會(huì)怎么處理接收的消息,可對(duì)msg.what彩匕、msg.obj腔剂、msg.arg1、msg,arg2驼仪、msg.getcallBack()即一個(gè)Runnable對(duì)象進(jìn)行處理)
Handler handler = new Handler(Looper.myLooper()){
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 0: textView.setText((String)msg.obj);
}
}
};
②:在另一個(gè)線程中定義一個(gè)Message對(duì)象并傳遞參數(shù)掸犬,最后send
private void start() {
new Thread(){
@Override
public void run() {
Message message = Message.obtain();
message.what = 0;
message.obj = getStringFromNet();
handler.sendMessage(message);
}
}.start();
}
不建議直接new Message,Message內(nèi)部保存了一個(gè)緩存的消息池绪爸,我們可以用obtain從緩存池獲得一個(gè)消息湾碎,Message使用完后系統(tǒng)會(huì)調(diào)用recycle回收,如果自己new很多Message奠货,每次使用完后系統(tǒng)放入緩存池介褥,會(huì)占用很多內(nèi)存的。
2.ThreadLocal理解
ThreadLocal類中有一個(gè)內(nèi)部類ThreadLocalMap递惋,而ThreadLocalMap類中又有一個(gè)內(nèi)部類Entry鍵值對(duì)
ThreadLocal中的set方法會(huì)創(chuàng)建一個(gè)map并為map設(shè)置鍵值對(duì)柔滔,傳入當(dāng)前ThreadLocal和Value即對(duì)應(yīng)需要保存的對(duì)象
而Thread類中有一個(gè)threadlocals變量,他是ThreadLocalMap類的實(shí)例
所以每個(gè)線程中都有一個(gè)threadLocals變量萍虽,這個(gè)變量存儲(chǔ)著ThreadLocal和對(duì)應(yīng)的需要保存的對(duì)象廊遍。
而在Looper類中,有一個(gè)ThreadLocal<Looper>的實(shí)例sThreadLocal贩挣,它的get方法就是返回每個(gè)線程所特有的Looper,它被final,static修飾王财,所以Looper中只會(huì)有一個(gè)Threadlocal實(shí)例卵迂,所以每個(gè)線程中sThreadLocal是唯一的。
但雖然每個(gè)線程中sThreadLocal是唯一的绒净,但是每個(gè)線程ThreadLocalMap是不同的见咒,所以不同的線程能得到不同的Looper。
2.HandlerThread理解:
Android應(yīng)用中的消息循環(huán)由Looper和Handler配合完成挂疆,Looper類用于封裝消息循環(huán)改览,類中有個(gè)MessageQueue消息隊(duì)列;Handler類封裝了消息投遞和消息處理等功能缤言。 系統(tǒng)默認(rèn)情況下只有主線程(即UI線程)綁定Looper對(duì)象宝当,因此在主線程中可以直接創(chuàng)建Handler的實(shí)例,但是在子線程中就不能直接new出Handler的實(shí)例了胆萧,因?yàn)樽泳€程默認(rèn)并沒有Looper對(duì)象庆揩,此時(shí)會(huì)拋出RuntimeException異常; 如果需要在子線程中使用Handler類跌穗,首先需要?jiǎng)?chuàng)建Looper類實(shí)例订晌,這時(shí)可以通過Looper.prepare()和Looper.loop()函數(shù)來實(shí)現(xiàn)的。通過閱讀Framework層源碼發(fā)現(xiàn)蚌吸,Android為我們提供了一個(gè)HandlerThread類锈拨,該類繼承Thread類,并使用上面兩個(gè)函數(shù)創(chuàng)建Looper對(duì)象羹唠,而且使用wait/notifyAll解決了多線程中子線程1獲取子線程2的Looper對(duì)象為空的問題奕枢。這樣便成功避免了上述的異常等問題。 詳見:http://tech.cncms.com/shouji/android/96016.html
3.同步屏障
參考:https://blog.csdn.net/afdafvdaa/article/details/116097327
當(dāng)有需要加急處理的異步消息時(shí)肉迫,需要用到同步屏障
在handler中一共有三種消息類型:
①同步消息验辞。也就是普通的消息。
②異步消息喊衫。通過setAsynchronous(true)設(shè)置的消息跌造。
③同步屏障消息。通過postSyncBarrier方法添加的消息族购,特點(diǎn)是target為空壳贪,也就是沒有對(duì)應(yīng)的handler。