本篇主要探討HandlerThread的基本使用以及原理解析
HandlerThread部分源碼
/**
* Handy class for starting a new thread that has a looper. The looper can then be
* used to create handler classes. Note that start() must still be called.
*/
public class HandlerThread extends Thread {
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
...省略部分代碼
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
...省略部分代碼
什么是HandlerThread?
正如源碼中,類注釋所述,一個擁有Looper
的靈活線程,可以使用這個Looper
來創(chuàng)建一個Handler.同常規(guī)線程一樣,Thread.start()
仍必須調(diào)用蟀淮。
如果獲取Looper?
通過(HandlerThread對象).getLooper()
即可獲取當(dāng)前HandlerThread
線程中關(guān)聯(lián)的Looper
.
如何退出或關(guān)閉ThreadHandler?
使用(HandlerThread對象).quit()
或(HandlerThread對象).quitSafely()
退出杂伟。
Demo示例-如何使用HandlerThread负懦?
Demo代碼如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final int HANDLER_THREAD_TASK_NO_1 = 1;
//工作線程
private HandlerThread mWorkThread;
//通過HandlerThread中的Looper創(chuàng)建的Handler.
private Handler mWorkHandler;
private View mBtSendTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtSendTask = findViewById(R.id.bt_send_task);
mBtSendTask.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Message message = new Message();
message.what = HANDLER_THREAD_TASK_NO_1;
Bundle bundle = new Bundle();
bundle.putString("account_id","123");
bundle.putString("name","mike");
message.setData(bundle);
mWorkHandler.sendMessage(message);
}
});
mWorkThread = new HandlerThread("work-Thread");
//同普通的線程一樣,必須調(diào)用start,讓run方法運(yùn)行起來,初始化Handler.
mWorkThread.start();
//使用工作線程中的Looper(HandlerThread中的)來構(gòu)建一個Handler
mWorkHandler = new Handler(mWorkThread.getLooper()){
/*
* 由于我們Handler的Looper是從HandlerThread中獲取到的,所以handleMessage會在子線中執(zhí)行拷肌。
* 我們可以通過傳遞的Message中來獲取相關(guān)參數(shù),并執(zhí)行異步任務(wù)金度。
* */
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Log.e(TAG,"當(dāng)前線程N(yùn)ame: "+Thread.currentThread().getName()); //E/MainActivity: 當(dāng)前線程N(yùn)ame: work-Thread
switch (msg.what) {
case HANDLER_THREAD_TASK_NO_1:
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Bundle data = msg.getData();
String account_id = data.getString("account_id");
String name = data.getString("name");
Log.e(TAG,"account: " + account_id + " name: "+name);
break;
}
}
};
}
@Override
protected void onDestroy() {
//使用完成后,關(guān)閉線程
mWorkThread.quit();
//清除handler中的消息
mWorkHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
}
HandlerThread使用于哪些場景?
目前想到的是:有很多任務(wù)要處理,但任務(wù)必須異步并按順序處理的情況怕膛。
理由:Handler
和Thread
的結(jié)合,提供了異步處理和任務(wù)消息隊列,可以很好的對任務(wù)進(jìn)行排隊朴上。
IntentService - 源碼中的HandlerThread使用
IntentService
,一種特殊的Service;可以處理異步耗時任務(wù),執(zhí)行完畢,自動關(guān)閉。
普通Service
是在主UI線程線程執(zhí)行,如果我們需要進(jìn)行耗時操作,則必須通過 new Thread()
來開啟一個線程來做耗時任務(wù)。
來看IntentService
的源碼部分:
public abstract class IntentService extends Service {
//HandlerThread中的Looper
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
//聲明一個類,ServiceHandler繼承自Handler
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
/*
如果我們使用IntentService,要關(guān)注的只有onHandleIntent,因?yàn)樗鼒?zhí)行在子線程(工作線程)
可以看到這里在調(diào)用完onHandleIntent后,即調(diào)用了 stopSelf().
那么我們重點(diǎn)需要關(guān)注的即是handleMessage所處的線程偏螺。
*/
@Override
public void handleMessage(Message msg) {
//收到傳遞的消息,進(jìn)行耗時任務(wù)
onHandleIntent((Intent)msg.obj);
//任務(wù)結(jié)束后關(guān)閉服務(wù)
stopSelf(msg.arg1);
}
}
//...省略代碼
@Override
public void onCreate() {
super.onCreate();
//這里創(chuàng)建了一個HandlerThread,并調(diào)用了start()
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//獲取了HandlerThread中的 Looper()
mServiceLooper = thread.getLooper();
//將獲取到的Looper()用來創(chuàng)建ServiceHandler,那么ServiceHandler即允許在Looper所在的線程
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
//將我們傳遞的消息,發(fā)送到隊列里,等待傳遞
mServiceHandler.sendMessage(msg);
}
//...省略代碼
}
可以看到IntentService
中的代碼還是比較清晰的行疏。步驟:
1.創(chuàng)建HandlerThread
,并調(diào)用start().
2.獲取HandlerThread
中的Looper
,創(chuàng)建任務(wù)處理的ServiceHandler
,并重寫handleMessage()
.
3.外部啟動服務(wù),onStart()
中獲取Intent
中的數(shù)據(jù),并構(gòu)建Message
對象,通過2中創(chuàng)建的ServiceHandler
發(fā)送消息。
4.通過HandlerThread
中run()
方法的Looper
輪詢處理消息,調(diào)用ServiceHandler
的handleMessage()
.
5.我們在onHandleIntent()
進(jìn)行耗時任務(wù)砖茸。結(jié)束后,服務(wù)自動關(guān)閉隘擎。
程序小白,偶爾寫寫,知識探究與記錄,有誤之處,望不吝賜教殴穴。