【android】HandlerThread的使用及源码剖析
16lz
2021-01-26
有时候我们需要在应用程序中创建一些 常驻的子线程不定期地执行一些计算型任务 ,这时候可以考虑使用HandlerThread,它具有 创建带消息循环的子线程 的作用。
一、HanderThread使用示例 先熟悉下HandlerThread的一般用法。我们创建一个如下所示的Activity: [java] view plain copy
二、HandlerThread源码剖析 HandlerThread源码十分精简。 HandlerThread继承自java.lang.Thread,并封装了Looper对象: [java] view plain copy
可通过构造器注入线程优先级,默认优先级为Process.THREAD_PRIORITY_DEFAULT [java] view plain copy
核心逻辑为run方法(复写Thread类的run方法): [java] view plain copy
外界可通过getLooper方法获取Looper对象: [java] view plain copy
如果调用getLooper方法时,Looper未准备好,那么将会阻塞线程,直到准备好Looper对象。 外界可调用quit方法终止消息循环: [java] view plain copy
附: Looper类相信大家都不陌生,这里顺便简单提下(之前写过Handler和Looper): Looper.prepare方法将会创建一个Looper对象(Looper类的构造器为私有,不可new),并将其放到ThreadLocal中,意为线程局部变量: [java] view plain copy
然后通过Looper.myLooper方法返回与本线程绑定的Looper,正是刚创建的Looper: [java] view plain copy
Looper.loop方法将启动消息循环,不断从其内部封装的消息队列MessageQueue中取出消息,交由Handler执行。
以上就是HandlerThread的全部内容。
转自:http://blog.csdn.net/chdjj/article/details/39063557
一、HanderThread使用示例 先熟悉下HandlerThread的一般用法。我们创建一个如下所示的Activity: [java] view plain copy
- packagecom.example.handlethreaddemo;
- importandroid.app.Activity;
- importandroid.os.Bundle;
- importandroid.os.Handler;
- importandroid.os.HandlerThread;
- importandroid.os.Looper;
- importandroid.os.Message;
- importandroid.util.Log;
- publicclassMainActivityextendsActivity
- {
- privateLoopermLooper;
- privateMyHandlermHandler;
- privatestaticfinalStringTAG="MainActivity";
- privatestaticclassMyHandlerextendsHandler
- {
- publicMyHandler(Looperlooper)
- {
- super(looper);
- }
- @Override
- publicvoidhandleMessage(Messagemsg)
- {
- switch(msg.what)
- {
- case1:
- Log.i(TAG,"当前线程是"+Thread.currentThread().getName()+",TEST1");
- break;
- case2:
- Log.i(TAG,"TEST2");
- break;
- }
- }
- }
- @Override
- protectedvoidonCreate(BundlesavedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- //创建HandlerThread对象
- HandlerThreadmyHandleThread=newHandlerThread("HandlerThread<子线程>");
- //启动HandlerThread---->内部将启动消息循环
- myHandleThread.start();
- //获取Looper
- mLooper=myHandleThread.getLooper();
- //构造Handler,传入子线程中的Looper
- mHandler=newMyHandler(mLooper);
- /*
- *注:经过上述步骤,Handler将绑定子线程的Looper和MessageQueue.
- *也就是说handleMessage最终由子线程调用
- **/
- mHandler.sendEmptyMessage(1);
- Log.i(TAG,"当前线程是:"+Thread.currentThread().getName());
- }
- }
使用HandlerThread内部提供的Looper对象构造Handler对象,然后在ui线程中向Handler发送消息。log日志如下:
可见发送消息的线程为UI线程,而处理消息的线程为子线程,也就是说,我们在 子线程中创建了消息循环。 一般情况下,我们总是在UI线程中创建Handler对象,并使用界面组件提供的默认Looper,这个Looper绑定在UI线程上。所以我们在线程中向Handler发送消息时,最终的处理是在主线程中进行的。但正如开篇所说,我们有时需要构建常驻的子线程以不定期执行计算型任务,这时在子线程中创建消息循环将非常有用。
二、HandlerThread源码剖析 HandlerThread源码十分精简。 HandlerThread继承自java.lang.Thread,并封装了Looper对象: [java] view plain copy
- intmPriority;//优先级
- intmTid=-1;//线程标志
- LoopermLooper;//消息循环
可通过构造器注入线程优先级,默认优先级为Process.THREAD_PRIORITY_DEFAULT [java] view plain copy
- publicHandlerThread(Stringname,intpriority){
- super(name);
- mPriority=priority;
- }
核心逻辑为run方法(复写Thread类的run方法): [java] view plain copy
- publicvoidrun(){
- mTid=Process.myTid();
- Looper.prepare();//创建Looper对象
- synchronized(this){
- mLooper=Looper.myLooper();//获取与本线程绑定的Looper
- notifyAll();
- }
- Process.setThreadPriority(mPriority);
- onLooperPrepared();//回调接口,默认为空实现。
- Looper.loop();//启动消息循环--->maybeblocked
- mTid=-1;
- }
外界可通过getLooper方法获取Looper对象: [java] view plain copy
- publicLoopergetLooper(){
- if(!isAlive()){//线程死亡
- returnnull;
- }
- //Ifthethreadhasbeenstarted,waituntilthelooperhasbeencreated.
- synchronized(this){
- while(isAlive()&&mLooper==null){
- try{
- wait();//异步等待Looper准备好
- }catch(InterruptedExceptione){
- }
- }
- }
- returnmLooper;
- }
如果调用getLooper方法时,Looper未准备好,那么将会阻塞线程,直到准备好Looper对象。 外界可调用quit方法终止消息循环: [java] view plain copy
- publicbooleanquit(){
- Looperlooper=getLooper();
- if(looper!=null){
- looper.quit();//内部调用looper类的quit
- returntrue;
- }
- returnfalse;
- }
附: Looper类相信大家都不陌生,这里顺便简单提下(之前写过Handler和Looper): Looper.prepare方法将会创建一个Looper对象(Looper类的构造器为私有,不可new),并将其放到ThreadLocal中,意为线程局部变量: [java] view plain copy
- publicstaticvoidprepare(){
- prepare(true);
- }
- privatestaticvoidprepare(booleanquitAllowed){
- if(sThreadLocal.get()!=null){
- thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread");
- }
- sThreadLocal.set(newLooper(quitAllowed));
- }
然后通过Looper.myLooper方法返回与本线程绑定的Looper,正是刚创建的Looper: [java] view plain copy
- publicstaticLoopermyLooper(){
- returnsThreadLocal.get();
- }
Looper.loop方法将启动消息循环,不断从其内部封装的消息队列MessageQueue中取出消息,交由Handler执行。
[java] view plain copy
- publicstaticvoidloop(){
- finalLooperme=myLooper();
- if(me==null){
- thrownewRuntimeException("NoLooper;Looper.prepare()wasn'tcalledonthisthread.");
- }
- finalMessageQueuequeue=me.mQueue;
- //Makesuretheidentityofthisthreadisthatofthelocalprocess,
- //andkeeptrackofwhatthatidentitytokenactuallyis.
- Binder.clearCallingIdentity();
- finallongident=Binder.clearCallingIdentity();
- for(;;){
- Messagemsg=queue.next();//mightblock
- if(msg==null){
- //Nomessageindicatesthatthemessagequeueisquitting.
- return;
- }
- //Thismustbeinalocalvariable,incaseaUIeventsetsthelogger
- Printerlogging=me.mLogging;
- if(logging!=null){
- logging.println(">>>>>Dispatchingto"+msg.target+""+
- msg.callback+":"+msg.what);
- }
- msg.target.dispatchMessage(msg);
- if(logging!=null){
- logging.println("<<<<<Finishedto"+msg.target+""+msg.callback);
- }
- //Makesurethatduringthecourseofdispatchingthe
- //identityofthethreadwasn'tcorrupted.
- finallongnewIdent=Binder.clearCallingIdentity();
- if(ident!=newIdent){
- Log.wtf(TAG,"Threadidentitychangedfrom0x"
- +Long.toHexString(ident)+"to0x"
- +Long.toHexString(newIdent)+"whiledispatchingto"
- +msg.target.getClass().getName()+""
- +msg.callback+"what="+msg.what);
- }
- msg.recycle();
- }
- }
没有消息时,消息队列会阻塞。
以上就是HandlerThread的全部内容。
转自:http://blog.csdn.net/chdjj/article/details/39063557
更多相关文章
- SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
- Android可以在子线程更新UI吗
- RxJava 学习笔记(四)
- Android(安卓)SQLiteOpenHelper的使用
- android-----AsyncTask源码分析
- 面试总结(6):ScheduledExecutorService的使用
- Android(java)同步方法synchronized
- Android之Context理解
- 最全面的安卓ANR