Android的HandlerThread详解

前言:

    一般的Thread都是一次性的,也就是当你需要执行耗时操作的时候就需要去开启一个新县城,耗时操作执行完成后
开启的线程也将被销毁掉,如果你的应用频繁的开启新线程和销毁线程,这是相当耗内存资源的,消耗过大后,就可能
造成应用ANR.为解决这个问题,可以实现一个循环线程,当有耗时操作需要执行的时候,就将耗时操作传递给循环线程
执行,当耗时操作执行完成后改变线程状态让它进入到等待状态。再有耗时操作的时候就唤醒线程执行。就这样重复的利用
就可以使线程利用性能大大提升了(本质就是消息循环+线程通信的东西)。
    上面的原理其实就是android中HandlerThread的原理了。
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

posted @ 2015-07-16 22:34  perfect亮  阅读(1101)  评论(0)    收藏  举报