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()就是为了解决这两个线程的同步问题。