zoukankan      html  css  js  c++  java
  • Android HandlerThread使用介绍以及源码解析

    摘要: 版权声明:本文出自汪磊的博客,转载请务必注明出处。


    一、HandlerThread的介绍及使用举例             
    HandlerThread是什么鬼?其本质就是一个线程,但是HandlerThread在启动的时候会帮我们准备好一个Looper,并供外界使用,说白了就是使我们在子线程中更方便的使用Handler,比如没有HandlerThread我们要在子线程使用Handler,写法如下:

     1 private Handler mHandler;
     2     
     3     @Override
     4     public void run() {
     5         super.run();
     6         
     7         Looper.prepare();
     8         
     9         mHandler = new Handler(){
    10             
    11             @Override
    12             public void handleMessage(Message msg) {
    13                 
    14             }
    15         };
    16         
    17         Looper.loop();
    18 } 

    有了HandlerThread就不用我们自己管理Looper了,至于为什么分析源码的时候就明白了。

    HandlerThread使用简单介绍:

    首先我们要初始化HandlerThread然后调用其start方法,也就是开启线程:

    1 mHandlerThread = new HandlerThread("mHandlerThread");//这里的mHandlerThread其实就是线程的名字
    2 mHandlerThread.start();

    接下来初始化一个Handler并且将mHandlerThread中的Looper作为构造函数参数传递给Handler:

    1 mHandler = new Handler(mHandlerThread.getLooper())

    这样就保证了Hnadler运行在子线程。并且需要在适合的时机调用HandlerThread的quit方法或quitSafely方法,如Activity销毁的时候:

    1 @Override
    2 protected void onDestroy() {
    3     //
    4     super.onDestroy();
    5     //释放资源
    6     mHandlerThread.quit();
    7 }

    quit()与quitSafely()方法比较(这里只说一些结论,源码可以自己查看):

    相同点:
    调用之后MessageQueue消息队列均不在接受新的消息加入队列。

    不同点:
    quit方法把MessageQueue消息池中所有的消息全部清空。quitSafely方法只会清空MessageQueue消息池中所有的延迟消息(延迟消息是指通过sendMessageDelayed或postDelayed等方法发送的消息),非延迟消息则不清除继续派发出去让Handler去处理。

    接下来我们完整看一下HandlerThread例子源码:

     1 public class MainActivity extends Activity {
     2 
     3     private HandlerThread mHandlerThread;
     4     private Handler mHandler;
     5     private boolean flag;
     6     //
     7 
     8     @Override
     9     protected void onCreate(Bundle savedInstanceState) {
    10         super.onCreate(savedInstanceState);
    11         setContentView(R.layout.activity_main);
    12 
    13         mHandlerThread = new HandlerThread("mHandlerThread");
    14         mHandlerThread.start();
    15 
    16         mHandler = new Handler(mHandlerThread.getLooper()) {
    17 
    18             @Override
    19             public void handleMessage(Message msg) {
    20                 //
    21                 try {
    22                     Thread.sleep(2000);
    23                 } catch (InterruptedException e) {
    24                     e.printStackTrace();
    25                 }
    26                 
    27                 if(flag){
    28                     Log.i("HandlerThread", "更新:"+new Random().nextInt(1000));
    29                 }
    30                 mHandler.sendEmptyMessage(1);
    31             }
    32         };
    33         
    34     }
    35     
    36     @Override
    37     protected void onResume() {
    38         //
    39         super.onResume();
    40         flag = true;
    41         mHandler.sendEmptyMessage(1);
    42     }
    43     
    44     @Override
    45     protected void onPause() {
    46         //
    47         super.onPause();
    48         flag = false;
    49     }
    50     
    51     @Override
    52     protected void onDestroy() {
    53         //
    54         super.onDestroy();
    55         //释放资源
    56         mHandlerThread.quit();
    57     }
    58 }

    运行程序就会在控制台看到每隔两秒有Log打出。至于HandlerThrea的使用就到此为止了,看懂上面小例子就差不多了。

    二、HandlerThread的源码分析

    HandlerThread源码非常简短,出去注释不到100行,这里就直接全部贴出来了:

     1 public class HandlerThread extends Thread {
     2     int mPriority;
     3     int mTid = -1;
     4     Looper mLooper;
     5 
     6     public HandlerThread(String name) {
     7         super(name);
     8         mPriority = Process.THREAD_PRIORITY_DEFAULT;
     9     }
    10     
    11     /**
    12      * Constructs a HandlerThread.
    13      * @param name
    14      * @param priority The priority to run the thread at. The value supplied must be from 
    15      * {@link android.os.Process} and not from java.lang.Thread.
    16      */
    17     public HandlerThread(String name, int priority) {
    18         super(name);
    19         mPriority = priority;
    20     }
    21     
    22     /**
    23      * Call back method that can be explicitly overridden if needed to execute some
    24      * setup before Looper loops.
    25      */
    26     protected void onLooperPrepared() {
    27     }
    28 
    29     @Override
    30     public void run() {
    31         mTid = Process.myTid();
    32         Looper.prepare();
    33         synchronized (this) {
    34             mLooper = Looper.myLooper();
    35             notifyAll();
    36         }
    37         Process.setThreadPriority(mPriority);
    38         onLooperPrepared();
    39         Looper.loop();
    40         mTid = -1;
    41     }
    42     
    43     /**
    44      * This method returns the Looper associated with this thread. If this thread not been started
    45      * or for any reason is isAlive() returns false, this method will return null. If this thread 
    46      * has been started, this method will block until the looper has been initialized.  
    47      * @return The looper.
    48      */
    49     public Looper getLooper() {
    50         if (!isAlive()) {
    51             return null;
    52         }
    53         
    54         // If the thread has been started, wait until the looper has been created.
    55         synchronized (this) {
    56             while (isAlive() && mLooper == null) {
    57                 try {
    58                     wait();
    59                 } catch (InterruptedException e) {
    60                 }
    61             }
    62         }
    63         return mLooper;
    64     }
    65 
    66     
    67     public boolean quit() {
    68         Looper looper = getLooper();
    69         if (looper != null) {
    70             looper.quit();
    71             return true;
    72         }
    73         return false;
    74     }
    75 
    76 
    77     public boolean quitSafely() {
    78         Looper looper = getLooper();
    79         if (looper != null) {
    80             looper.quitSafely();
    81             return true;
    82         }
    83         return false;
    84     }
    85 
    86     /**
    87      * Returns the identifier of this thread. See Process.myTid().
    88      */
    89     public int getThreadId() {
    90         return mTid;
    91     }
    92 }

    看第一行就知道了其本质就是一个线程。

    6-9行以及17-20行构造函数,也很简单,就是初始化的时候我们可以定义线程名字,还可以传入线程优先级。

    初始化完成,紧接着调用start()开发线程就会执行run方法逻辑。

    30-41行代码,最重要的就是调用Looper.prepare()以及Looper.loop()方法为我们在子线程准备好一个Looper。并且用变量mLooper记录,调用getLooper()方法的时候返回。

    但是,细心的你肯定发现run()方法中有个notifyAll(),getLooper()中有个wait()为什么要加这些鸟玩意?

    大家发现没在HandlerThread 例子中Handler的创建是在主线程完成的,创建的时候需要调用HandlerThread的getLooper()获取mLooper作为参数传递给Handler的构造函数,而Looper的创建是在子线程中创建的,这里就有线程同步问题了,比如我们调用getLooper()的时候HandlerThread中run()方法还没执行完,mLooper变量还未赋值,此时就执行了wait()等待逻辑,一直等到run()方法中mLooper被赋值,之后立即执行notifyAll(),然后getLooper()就可以正确返回mLooper了。

    明白了吧,不明的话这里需要花些时间好好理解下,好了源码主要部分就分析完了,看到这里相信你对HandlerThread有了一定的了解了

    HandlerThread 还是比较简单理解的,好了,本篇到此为止,希望对你有帮助。

  • 相关阅读:
    java使用io流读取windows文件乱码问题
    java的io字符流关闭和刷新.flush();
    java使用io流实现图片复制
    java8新特性-函数式接口详细讲解及案例
    java8的lambda过滤list遍历集合,排序
    java复制对象,复制对象属性,只可复制两个对象想同的属性名。也可自定义只复制需要的属性。
    详讲KMP算法
    java栈和队列
    请求中文乱码解决
    idea创建servlet步骤
  • 原文地址:https://www.cnblogs.com/leipDao/p/8005520.html
Copyright © 2011-2022 走看看