有时候我们需要在应用程序中创建一些 常驻的子线程不定期地执行一些计算型任务 ,这时候可以考虑使用HandlerThread,它具有 创建带消息循环的子线程 的作用。
一、HanderThread使用示例 先熟悉下HandlerThread的一般用法。我们创建一个如下所示的Activity: [java] view plain copy
  1. packagecom.example.handlethreaddemo;
  2. importandroid.app.Activity;
  3. importandroid.os.Bundle;
  4. importandroid.os.Handler;
  5. importandroid.os.HandlerThread;
  6. importandroid.os.Looper;
  7. importandroid.os.Message;
  8. importandroid.util.Log;
  9. publicclassMainActivityextendsActivity
  10. {
  11. privateLoopermLooper;
  12. privateMyHandlermHandler;
  13. privatestaticfinalStringTAG="MainActivity";
  14. privatestaticclassMyHandlerextendsHandler
  15. {
  16. publicMyHandler(Looperlooper)
  17. {
  18. super(looper);
  19. }
  20. @Override
  21. publicvoidhandleMessage(Messagemsg)
  22. {
  23. switch(msg.what)
  24. {
  25. case1:
  26. Log.i(TAG,"当前线程是"+Thread.currentThread().getName()+",TEST1");
  27. break;
  28. case2:
  29. Log.i(TAG,"TEST2");
  30. break;
  31. }
  32. }
  33. }
  34. @Override
  35. protectedvoidonCreate(BundlesavedInstanceState)
  36. {
  37. super.onCreate(savedInstanceState);
  38. setContentView(R.layout.activity_main);
  39. //创建HandlerThread对象
  40. HandlerThreadmyHandleThread=newHandlerThread("HandlerThread<子线程>");
  41. //启动HandlerThread---->内部将启动消息循环
  42. myHandleThread.start();
  43. //获取Looper
  44. mLooper=myHandleThread.getLooper();
  45. //构造Handler,传入子线程中的Looper
  46. mHandler=newMyHandler(mLooper);
  47. /*
  48. *注:经过上述步骤,Handler将绑定子线程的Looper和MessageQueue.
  49. *也就是说handleMessage最终由子线程调用
  50. **/
  51. mHandler.sendEmptyMessage(1);
  52. Log.i(TAG,"当前线程是:"+Thread.currentThread().getName());
  53. }
  54. }

使用HandlerThread内部提供的Looper对象构造Handler对象,然后在ui线程中向Handler发送消息。log日志如下:


可见发送消息的线程为UI线程,而处理消息的线程为子线程,也就是说,我们在 子线程中创建了消息循环。 一般情况下,我们总是在UI线程中创建Handler对象,并使用界面组件提供的默认Looper,这个Looper绑定在UI线程上。所以我们在线程中向Handler发送消息时,最终的处理是在主线程中进行的。但正如开篇所说,我们有时需要构建常驻的子线程以不定期执行计算型任务,这时在子线程中创建消息循环将非常有用。
二、HandlerThread源码剖析 HandlerThread源码十分精简。 HandlerThread继承自java.lang.Thread,并封装了Looper对象: [java] view plain copy
  1. intmPriority;//优先级
  2. intmTid=-1;//线程标志
  3. LoopermLooper;//消息循环

可通过构造器注入线程优先级,默认优先级为Process.THREAD_PRIORITY_DEFAULT [java] view plain copy
  1. publicHandlerThread(Stringname,intpriority){
  2. super(name);
  3. mPriority=priority;
  4. }

核心逻辑为run方法(复写Thread类的run方法): [java] view plain copy
  1. publicvoidrun(){
  2. mTid=Process.myTid();
  3. Looper.prepare();//创建Looper对象
  4. synchronized(this){
  5. mLooper=Looper.myLooper();//获取与本线程绑定的Looper
  6. notifyAll();
  7. }
  8. Process.setThreadPriority(mPriority);
  9. onLooperPrepared();//回调接口,默认为空实现。
  10. Looper.loop();//启动消息循环--->maybeblocked
  11. mTid=-1;
  12. }

外界可通过getLooper方法获取Looper对象: [java] view plain copy
  1. publicLoopergetLooper(){
  2. if(!isAlive()){//线程死亡
  3. returnnull;
  4. }
  5. //Ifthethreadhasbeenstarted,waituntilthelooperhasbeencreated.
  6. synchronized(this){
  7. while(isAlive()&&mLooper==null){
  8. try{
  9. wait();//异步等待Looper准备好
  10. }catch(InterruptedExceptione){
  11. }
  12. }
  13. }
  14. returnmLooper;
  15. }

如果调用getLooper方法时,Looper未准备好,那么将会阻塞线程,直到准备好Looper对象。 外界可调用quit方法终止消息循环: [java] view plain copy
  1. publicbooleanquit(){
  2. Looperlooper=getLooper();
  3. if(looper!=null){
  4. looper.quit();//内部调用looper类的quit
  5. returntrue;
  6. }
  7. returnfalse;
  8. }

附: Looper类相信大家都不陌生,这里顺便简单提下(之前写过Handler和Looper): Looper.prepare方法将会创建一个Looper对象(Looper类的构造器为私有,不可new),并将其放到ThreadLocal中,意为线程局部变量: [java] view plain copy
  1. publicstaticvoidprepare(){
  2. prepare(true);
  3. }
  4. privatestaticvoidprepare(booleanquitAllowed){
  5. if(sThreadLocal.get()!=null){
  6. thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread");
  7. }
  8. sThreadLocal.set(newLooper(quitAllowed));
  9. }

然后通过Looper.myLooper方法返回与本线程绑定的Looper,正是刚创建的Looper: [java] view plain copy
  1. publicstaticLoopermyLooper(){
  2. returnsThreadLocal.get();
  3. }

Looper.loop方法将启动消息循环,不断从其内部封装的消息队列MessageQueue中取出消息,交由Handler执行。

[java] view plain copy
  1. publicstaticvoidloop(){
  2. finalLooperme=myLooper();
  3. if(me==null){
  4. thrownewRuntimeException("NoLooper;Looper.prepare()wasn'tcalledonthisthread.");
  5. }
  6. finalMessageQueuequeue=me.mQueue;
  7. //Makesuretheidentityofthisthreadisthatofthelocalprocess,
  8. //andkeeptrackofwhatthatidentitytokenactuallyis.
  9. Binder.clearCallingIdentity();
  10. finallongident=Binder.clearCallingIdentity();
  11. for(;;){
  12. Messagemsg=queue.next();//mightblock
  13. if(msg==null){
  14. //Nomessageindicatesthatthemessagequeueisquitting.
  15. return;
  16. }
  17. //Thismustbeinalocalvariable,incaseaUIeventsetsthelogger
  18. Printerlogging=me.mLogging;
  19. if(logging!=null){
  20. logging.println(">>>>>Dispatchingto"+msg.target+""+
  21. msg.callback+":"+msg.what);
  22. }
  23. msg.target.dispatchMessage(msg);
  24. if(logging!=null){
  25. logging.println("<<<<<Finishedto"+msg.target+""+msg.callback);
  26. }
  27. //Makesurethatduringthecourseofdispatchingthe
  28. //identityofthethreadwasn'tcorrupted.
  29. finallongnewIdent=Binder.clearCallingIdentity();
  30. if(ident!=newIdent){
  31. Log.wtf(TAG,"Threadidentitychangedfrom0x"
  32. +Long.toHexString(ident)+"to0x"
  33. +Long.toHexString(newIdent)+"whiledispatchingto"
  34. +msg.target.getClass().getName()+""
  35. +msg.callback+"what="+msg.what);
  36. }
  37. msg.recycle();
  38. }
  39. }

没有消息时,消息队列会阻塞。
以上就是HandlerThread的全部内容。


转自:http://blog.csdn.net/chdjj/article/details/39063557

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. Android可以在子线程更新UI吗
  3. RxJava 学习笔记(四)
  4. Android(安卓)SQLiteOpenHelper的使用
  5. android-----AsyncTask源码分析
  6. 面试总结(6):ScheduledExecutorService的使用
  7. Android(java)同步方法synchronized
  8. Android之Context理解
  9. 最全面的安卓ANR

随机推荐

  1. AndroidStudio3.0及其以上集成ButterKnif
  2. Android(安卓)Banner简单使用
  3. Android(安卓)greenDAO数据库配置教程
  4. Android(安卓)Intent定义选择器打开相机
  5. Android(安卓)如何使用tcpdump抓包
  6. Android(安卓)Studio: “Error initializ
  7. 查看远程android设备数据库
  8. contentProvider操作
  9. 2010.10.15 Google Android(安卓)Worksho
  10. View Touch 事件分发