Thread、Handler和HandlerThread关系详解

 更新时间:2016年09月19日 09:26:23   作者:SillyMonkey  
这篇文章主要介绍了Thread、Handler和HandlerThread关系详解的相关资料,需要的朋友可以参考下

前言

前几天看到一道面试题:Thread、Handler和HandlerThread有什么区别?,这个题目有点意思,对于很多人来说,可能对Thread和Handler很熟悉,主要涉及到Android的消息机制(Handler、Message、Looper、MessageQueue),详见《 从Handler.post(Runnable r)再一次梳理Android的消息机制(以及handler的内存泄露)》

但是这个HandlerThread是拿来做什么的呢?它是Handler还是Thread?我们知道Handler是用来异步更新UI的,更详细的说是用来做线程间的通信的,更新UI时是子线程与UI主线程之间的通信。那么现在我们要是想子线程与子线程之间的通信要怎么做呢?当然说到底也是用Handler+Thread来完成(不推荐,需要自己操作Looper),Google官方很贴心的帮我们封装好了一个类,那就是刚才说到的:HandlerThread。(类似的封装对于多线程的场景还有AsyncTask)

使用方法

还是先来看看HandlerThread的使用方法:
首先新建HandlerThread并且执行start()

private HandlerThread mHandlerThread;
......
mHandlerThread = new HandlerThread("HandlerThread");
handlerThread.start();

创建Handler,使用mHandlerThread.getLooper()生成Looper:

 final Handler handler = new Handler(mHandlerThread.getLooper()){
   @Override
   public void handleMessage(Message msg) {
    System.out.println("收到消息");
   }
  };

然后再新建一个子线程来发送消息:

 new Thread(new Runnable() {
   @Override
   public void run() {
    try {
     Thread.sleep(1000);//模拟耗时操作
     handler.sendEmptyMessage(0);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
  }).start();

最后一定不要忘了在onDestroy释放,避免内存泄漏:

 @Override
 protected void onDestroy() {
  super.onDestroy();
  mHandlerThread.quit();
 }

执行结果很简单,就是在控制台打印字符串:收到消息

原理

整个的使用过程我们根本不用去关心Handler相关的东西,只需要发送消息,处理消息,Looper相关的东西交给它自己去处理,还是来看看源码它是怎么实现的,先看构造方法:

public class HandlerThread extends Thread {}

HandlerThread其实还是一个线程,它跟普通线程有什么不同?

public class HandlerThread extends Thread {
 int mPriority;
 int mTid = -1;
 Looper mLooper;

 public HandlerThread(String name) {
  super(name);
  mPriority = Process.THREAD_PRIORITY_DEFAULT;
 }
 ......
}

答案是多了一个Looper,这个是子线程独有的Looper,用来做消息的取出和处理。继续看看HandlerThread这个线程的run方法: 

 protected void onLooperPrepared() {
 }
 @Override
 public void run() {
  mTid = Process.myTid();
  Looper.prepare();
  synchronized (this) {
   mLooper = Looper.myLooper();//生成Looper
   notifyAll();
  }
  Process.setThreadPriority(mPriority);
  onLooperPrepared();//空方法,在Looper创建完成后调用,可以自己重写逻辑
  Looper.loop();//死循环,不断从MessageQueue中取出消息并且交给Handler处理
  mTid = -1;
 }

主要就是做了一些Looper的操作,如果我们自己使用Handler+Thread来实现的话也要进行这个操作,再来看看getLooper()方法:   

public Looper getLooper() {
  if (!isAlive()) {
   return null;
  }

  // If the thread has been started, wait until the looper has been created.
  synchronized (this) {
   while (isAlive() && mLooper == null) {
    try {
     wait();
    } catch (InterruptedException e) {
    }
   }
  }
  return mLooper;
 }

方法很简单,就是加了个同步锁,如果已经创建了(isAlive()返回true)但是mLooper为空的话就继续等待,直到mLooper创建成功,最后看看quit方法,值得一提的是有两个:

 public boolean quit() {
  Looper looper = getLooper();
  if (looper != null) {
   looper.quit();
   return true;
  }
  return false;
 }
 public boolean quitSafely() {
  Looper looper = getLooper();
  if (looper != null) {
   looper.quitSafely();
   return true;
  }
  return false;
 }

quitSafely是针对在消息队列中还有消息或者是延迟发送的消息没有处理的情况,调用这个方法后都会被停止掉。

总结

HandlerThread的使用方法还是比较简单的,但是我们要明白一点的是:如果一个线程要处理消息,那么它必须拥有自己的Looper,并不是Handler在哪里创建,就可以在哪里处理消息的。

如果不用HandlerThread的话,需要手动去调用Looper.prepare()和Looper.loop()这些方法。

以上就是对Thread、Handler和HandlerThread关系 的资料整理,后续继续补充相关资料,谢谢大家对本站的支持!

相关文章

  • Android高仿IOS 滚轮选择控件

    Android高仿IOS 滚轮选择控件

    这篇文章主要为大家详细介绍了Android 高仿IOS滚轮选择控件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • Android编程实现带有图标的ListView并带有长按菜单效果示例

    Android编程实现带有图标的ListView并带有长按菜单效果示例

    这篇文章主要介绍了Android编程实现带有图标的ListView并带有长按菜单效果,结合实例形式分析了Android带图标的ListView及菜单功能相关实现技巧,需要的朋友可以参考下
    2017-06-06
  • Android中Glide获取图片Path、Bitmap用法详解

    Android中Glide获取图片Path、Bitmap用法详解

    这篇文章主要介绍了Android中Glide获取图片Path、Bitmap用法以及代码分析,需要的朋友们参考一下吧。
    2017-12-12
  • Android string.xml中的替换方法

    Android string.xml中的替换方法

    这篇文章主要介绍了Android string.xml中的替换方法,结合实例形式简单分析了string.xml中变量替换的相关技巧,需要的朋友可以参考下
    2016-01-01
  • Android实现自定义滑动式抽屉菜单效果

    Android实现自定义滑动式抽屉菜单效果

    这篇文章主要为大家详细介绍了Android实现自定义滑动式抽屉效果菜单,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-05-05
  • Android PopupWindow全屏详细介绍及实例代码

    Android PopupWindow全屏详细介绍及实例代码

    这篇文章主要介绍了 Android PopupWindow全屏详细介绍及实例代码的相关资料,需要的朋友可以参考下
    2016-12-12
  • Android仿新浪微博自定义ListView下拉刷新(4)

    Android仿新浪微博自定义ListView下拉刷新(4)

    这篇文章主要为大家详细介绍了Android仿新浪微博自定义ListView下拉刷新,重点介绍了Adapter的详细代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-11-11
  • Android使用硬件加速的方式

    Android使用硬件加速的方式

    硬件加速是指利用设备的硬件资源来加速图形渲染和图像处理等操作,以提高应用程序的性能和用户体验,Android使用硬件加速的目的是为了提高图形渲染的性能和效果,本文给大家详细介绍了Android如何使用硬件加速,需要的朋友可以参考下
    2023-10-10
  • Android开发之资源文件用法实例总结

    Android开发之资源文件用法实例总结

    这篇文章主要介绍了Android开发之资源文件用法,结合实例形式总结分析了Android开发过程中针对资源文件的常见操作技巧,需要的朋友可以参考下
    2016-02-02
  • Android 7.0以上版本实现应用内语言切换的方法

    Android 7.0以上版本实现应用内语言切换的方法

    本篇文章主要介绍了Android 7.0以上版本实现应用内语言切换的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02

最新评论