Android HandlerThread的使用及原理详解
一、HandlerThread的含义
HandlerThread能够新建拥有Looper的线程。这个Looper能够用来新建其他的Handler。(线程中的Looper)需要注意的是,新建的时候需要被回调。
二、HandlerThread的用法
一般情况下,我们会经常用Handler在子线程中更新UI线程,那是因为在主线程中有Looper循环,而HandlerThread新建拥有Looper的子线程又有什么用呢?
必然是执行耗时操作。举个例子,数据实时更新,我们每10秒需要切换一下显示的数据,如果我们将这种长时间的反复调用操作放到UI线程中,虽说可以执行,但是这样的操作多了之后,很容易会让UI线程卡顿甚至崩溃。
于是,就必须在子线程中调用这些了。
HandlerThread继承自Thread,一般适应的场景,便是集Thread和Handler之所长,适用于会长时间在后台运行,并且间隔时间内(或适当情况下)会调用的情况,比如上面所说的实时更新。
三、实现每2秒更新一下UI
publicclassMainActivityextendsAppCompatActivity{
privateTextViewtvMain;
privateHandlerThreadmHandlerThread;
//子线程中的handler
privateHandlermThreadHandler;
//UI线程中的handler
privateHandlermMainHandler=newHandler();
//以防退出界面后Handler还在执行
privatebooleanisUpdateInfo;
//用以表示该handler的常熟
privatestaticfinalintMSG_UPDATE_INFO=0x110;
@Override
protectedvoidonCreate(BundlesavedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvMain=(TextView)findViewById(R.id.tv_main);
initThread();
}
privatevoidinitThread()
{
mHandlerThread=newHandlerThread("check-message-coming");
mHandlerThread.start();
mThreadHandler=newHandler(mHandlerThread.getLooper())
{
@Override
publicvoidhandleMessage(Messagemsg)
{
update();//模拟数据更新
if(isUpdateInfo)
mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
}
};
}
privatevoidupdate()
{
try
{
//模拟耗时
Thread.sleep(2000);
mMainHandler.post(newRunnable()
{
@Override
publicvoidrun()
{
Stringresult="每隔2秒更新一下数据:";
result+=Math.random();
tvMain.setText(result);
}
});
}catch(InterruptedExceptione)
{
e.printStackTrace();
}
}
@Override
protectedvoidonResume()
{
super.onResume();
//开始查询
isUpdateInfo=true;
mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);
}
@Override
protectedvoidonPause()
{
super.onPause();
//停止查询
//以防退出界面后Handler还在执行
isUpdateInfo=false;
mThreadHandler.removeMessages(MSG_UPDATE_INFO);
}
@Override
protectedvoidonDestroy()
{
super.onDestroy();
//释放资源
mHandlerThread.quit();
}
}
四、HandlerThread原理
publicclassHandlerThreadextendsThread{
intmPriority;
intmTid=-1;
LoopermLooper;
publicHandlerThread(Stringname){
super(name);
mPriority=Process.THREAD_PRIORITY_DEFAULT;
}
publicHandlerThread(Stringname,intpriority){
super(name);
mPriority=priority;
}
protectedvoidonLooperPrepared(){
}
@Override
publicvoidrun(){
mTid=Process.myTid();
Looper.prepare();
synchronized(this){
mLooper=Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid=-1;
}
publicLoopergetLooper(){
if(!isAlive()){
returnnull;
}
//Ifthethreadhasbeenstarted,waituntilthelooperhasbeencreated.
synchronized(this){
while(isAlive()&&mLooper==null){
try{
wait();
}catch(InterruptedExceptione){
}
}
}
returnmLooper;
}
publicbooleanquit(){
Looperlooper=getLooper();
if(looper!=null){
looper.quit();
returntrue;
}
returnfalse;
}
publicbooleanquitSafely(){
Looperlooper=getLooper();
if(looper!=null){
looper.quitSafely();
returntrue;
}
returnfalse;
}
publicintgetThreadId(){
returnmTid;
}
}
首先我们可以看到HandlerThread继承自Thread,因此在run()中的逻辑都是在子线程中运行的。
接下来就是两个关键的方法,run()和getLooper():
run()中可以看到是很简单的创建Looper以及让Looper工作的逻辑。
run()里面当mLooper创建完成后有个notifyAll(),getLooper()中有个wait(),这有什么用呢?因为的mLooper在一个线程中执行创建,而我们的handler是在UI线程中调用getLooper()初始化的。
也就是说,我们必须等到mLooper创建完成,才能正确的返回。getLooper();wait(),notify()就是为了解决这两个线程的同步问题。