Android的HandlerThread详解
前言:
HandlerThread其实是一个线程,只不过其内部帮你实现了一个Looper的循环而已。那么我们
先来了解一下Handler是怎么使用的吧!
HandlerThread实现过程是:在andlerThread中子线程中初始化Looper(只有主线程不用初始化Looper,它自带的有),Looper对应它线程所属的Handler,也就是handler处理message的
是在子线程中执行的。message处理完后的子线程进入wait状态并将出了后的数据在传递给主线程的handler在进行处理。如果有新的操作先notify子线程在重复上述过程即可。
HandlerThread使用步骤(严格遵循):
1.创建实例对象
1 HandlerThread handlerThread = new HandlerThread("handlerThread");
以上参数可以任意字符串,参数的作用主要是标记当前线程的名字。
2.启动HandlerThread线程
1 handlerThread.start();
到此,我们就构建完一个循环线程了。那么你可能会怀疑,那我怎么将一个耗时的异步任务投放到HandlerThread线程中去执行呢?当然是有办法的,接下来看第三部。
3.构建循环消息处理机制
1 Handler subHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() { 2 @Override 3 public boolean handleMessage(Message msg) { 4 //实现自己的消息处理 5 return true; 6 } 7 });
第三步创建一个Handler对象,将上面HandlerThread中的looper对象最为Handler的参数,然后重写Handler的Callback接口类中的
handlerMessage方法来处理耗时任务。
总结:以上三步顺序不能乱,必须严格按照步骤来。到此,我们就可以调用subHandler以发送消息的形式发送耗时任务到线程
HandlerThread中去执行。言外之意就是subHandler中Callback接口类中的handlerMessage方法其实是在工作线程中执行的。
HandlerThread实例:
1 public class MainActivity extends Activity { 2 3 private Handler mSubHandler; 4 private TextView textView; 5 private Button button; 6 7 private Handler.Callback mSubCallback = new Handler.Callback() { 8 //该接口的实现就是处理异步耗时任务的,因此该方法执行在子线程中 9 @Override 10 public boolean handleMessage(Message msg) { 11 12 switch (msg.what) { 13 case 0: 14 Message msg1 = new Message(); 15 msg1.what = 0; 16 msg1.obj = java.lang.System.currentTimeMillis(); 17 mUIHandler.sendMessage(msg1); 18 break; 19 20 default: 21 break; 22 } 23 24 return false; 25 } 26 }; 27 28 @Override 29 protected void onCreate(Bundle savedInstanceState) { 30 super.onCreate(savedInstanceState); 31 setContentView(R.layout.activity_main); 32 33 textView = (TextView) findViewById(R.id.textView); 34 button = (Button) findViewById(R.id.button); 35 36 HandlerThread workHandle = new HandlerThread("workHandleThread"); 37 workHandle.start(); 38 mSubHandler = new Handler(workHandle.getLooper(), mSubCallback); 39 40 button.setOnClickListener(new OnClickListener() { 41 42 @Override 43 public void onClick(View v) { 44 //投放异步耗时任务到HandlerThread中 45 mSubHandler.sendEmptyMessage(0); 46 } 47 }); 48 49 } 50 }
HandlerThread源码分析
HandlerThread构造方法
1 /** 2 * Handy class for starting a new thread that has a looper. The looper can then be 3 * used to create handler classes. Note that start() must still be called. 4 */ 5 public class HandlerThread extends Thread { 6 //线程优先级 7 int mPriority; 8 //当前线程id 9 int mTid = -1; 10 //当前线程持有的Looper对象 11 Looper mLooper; 12 13 //构造方法 14 public HandlerThread(String name) { 15 //调用父类默认的方法创建线程 16 super(name); 17 mPriority = Process.THREAD_PRIORITY_DEFAULT; 18 } 19 //带优先级参数的构造方法 20 public HandlerThread(String name, int priority) { 21 super(name); 22 mPriority = priority; 23 } 24 25 ............... 26 27 }
分析:该类开头就给出了一个描述:该类用于创建一个带Looper循环的线程,Looper对象用于创建Handler对象,值得注意的是在创建Handler
对象之前需要调用start()方法启动线程。这里可能有些人会有疑问?为啥需要先调用start()方法之后才能创建Handler呢?后面我们会解答。
上面的代码注释已经很清楚了,HandlerThread类有两个构造方法,不同之处就是设置当前线程的优先级参数。你可以根据自己的情况来设置优先
级,也可以使用默认优先级。
HandlerThrad的run方法
1 public class HandlerThread extends Thread { 2 /** 3 * Call back method that can be explicitly overridden if needed to execute some 4 * setup before Looper loops. 5 */ 6 protected void onLooperPrepared() { 7 } 8 9 @Override 10 public void run() { 11 //获得当前线程的id 12 mTid = Process.myTid(); 13 //准备循环条件 14 Looper.prepare(); 15 //持有锁机制来获得当前线程的Looper对象 16 synchronized (this) { 17 mLooper = Looper.myLooper(); 18 //发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLooper方法中的wait 19 notifyAll(); 20 } 21 //设置当前线程的优先级 22 Process.setThreadPriority(mPriority); 23 //该方法实现体是空的,子类可以实现该方法,作用就是在线程循环之前做一些准备工作,当然子类也可以不实现。 24 onLooperPrepared(); 25 //启动loop 26 Looper.loop(); 27 mTid = -1; 28 } 29 }
分析:以上代码中的注释已经写得很清楚了,以上run方法主要作用就是调用了Looper.prepare和Looper.loop构建了一个循环线程。值得一提的
是,run方法中在启动loop循环之前调用了onLooperPrepared方法,该方法的实现是一个空的,用户可以在子类中实现该方法。该方法的作用是
在线程loop之前做一些初始化工作,当然你也可以不实现该方法,具体看需求。
HandlerThread的其他方法
getLooper获得当前线程的Looper对象
1 /** 2 * This method returns the Looper associated with this thread. If this thread not been started 3 * or for any reason is isAlive() returns false, this method will return null. If this thread 4 * has been started, this method will block until the looper has been initialized. 5 * @return The looper. 6 */ 7 public Looper getLooper() { 8 //如果线程不是存活的,则直接返回null 9 if (!isAlive()) { 10 return null; 11 } 12 13 // If the thread has been started, wait until the looper has been created. 14 //如果线程已经启动,但是Looper还未创建的话,就等待,知道Looper创建成功 15 synchronized (this) { 16 while (isAlive() && mLooper == null) { 17 try { 18 wait(); 19 } catch (InterruptedException e) { 20 } 21 } 22 } 23 return mLooper; 24 }
分析:其实方法开头的英文注释已经解释的很清楚了:该方法主要作用是获得当前HandlerThread线程中的mLooper对象。
首先判断当前线程是否存活,如果不是存活的,这直接返回null。其次如果当前线程存活的,在判断线程的成员变量mLooper是否为null,如果为
null,说明当前线程已经创建成功,但是还没来得及创建Looper对象,因此,这里会调用wait方法去等待,当run方法中的notifyAll方法调用之后
通知当前线程的wait方法等待结束,跳出循环,获得mLooper对象的值。
总结:在获得mLooper对象的时候存在一个同步的问题,只有当线程创建成功并且Looper对象也创建成功之后才能获得mLooper的值。这里等待方法wait和run方法中的notifyAll方法共同完成同步问题。
quit结束当前线程的循环
1 /** 2 * Quits the handler thread's looper. 3 * <p> 4 * Causes the handler thread's looper to terminate without processing any 5 * more messages in the message queue. 6 * </p><p> 7 * Any attempt to post messages to the queue after the looper is asked to quit will fail. 8 * For example, the {@link Handler#sendMessage(Message)} method will return false. 9 * </p><p class="note"> 10 * Using this method may be unsafe because some messages may not be delivered 11 * before the looper terminates. Consider using {@link #quitSafely} instead to ensure 12 * that all pending work is completed in an orderly manner. 13 * </p> 14 * 15 * @return True if the looper looper has been asked to quit or false if the 16 * thread had not yet started running. 17 * 18 * @see #quitSafely 19 */ 20 public boolean quit() { 21 Looper looper = getLooper(); 22 if (looper != null) { 23 looper.quit(); 24 return true; 25 } 26 return false; 27 } 28 //安全退出循环 29 public boolean quitSafely() { 30 Looper looper = getLooper(); 31 if (looper != null) { 32 looper.quitSafely(); 33 return true; 34 } 35 return false; 36 }
分析:以上有两种让当前线程退出循环的方法,一种是安全的,一中是不安全的。至于两者有什么区别? quitSafely方法效率比quit方法标率低一点,但是安全。具体选择哪种就要看具体项目了。
总结:
1.HandlerThread适用于构建循环线程。
2.在创建Handler作为HandlerThread线程消息执行者的时候必须调用start方法之后,因为创建Handler需要的 Looper参数是从HandlerThread类中获得,而Looper对象的赋值又是在HandlerThread的run方法中创建。
3.关于HandlerThread和Service的结合使用请参考另一篇博客:Android IntentService 源码分析
参考地址:http://blog.csdn.net/feiduclear_up/article/details/46840523

浙公网安备 33010602011771号