前言

有些同学老问我,快要校招了 今年的金三银四退成了金四银五了,我改准备哪些知识点去面试复习,然而要准备的知识点很庞大,今天要讲的知识其中之一。一篇关于HandlerThread的解析

文档笔记~

知识汇总的PDF相关内容后续GitHub更新,想冲击金三银四的小伙伴可以找找看看,欢迎star
顺手留下GitHub链接,需要获取相关面试等内容的可以自己去找
https://github.com/xiangjiana/Android-MS
更多完整项目下载。未完待续。源码。图文知识后续上传github。
可以点击关于我联系我获取

使用场景

HandlerThread是Google帮我们封装好的,可以用来执行多个耗时操作,而不需要 多次开启线程,里面是采用HandlerLooper实现的。

Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called

怎样使用HandlerThread

1. 创建HandlerThread的实例对象
  HandlerThread handlerThread = new HandlerThread("myHandlerThread" );

该参数表示线程的名字,可以随便选择。

1. 启动我们创建的HandlerThread线程
  handlerThread.start();

将我们的handlerThread与Handler绑定在一起。 还记得是怎样将Handler与线 程对象绑定在一起的吗?其实很简单,就是将线程的looperHandler绑定在一 起,代码如下:

  mThreadHandler = new Handler(mHandlerThread.getLooper()) { @Override public void handleMessage(Message msg) { checkForUpdate(); if(isUpdate){ mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO); } }};

注意必须按照以上三个步骤来,下面在讲解源码的时候会分析其原因

完整测试代码如下

  public class MainActivity extends AppCompatActivity { private static final int MSG_UPDATE_INFO = 0x100; Handler mMainHandler = new Handler(); private TextView mTv; private Handler mThreadHandler; private HandlerThread mHandlerThread; private boolean isUpdate = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTv = (TextView) findViewById(R.id.tv); initHandlerThread(); }private void initHandlerThread() {mHandlerThread = new HandlerThread("xujun"); mHandlerThread.start(); mThreadHandler = new Handler(mHandlerThread.getLooper()) { @Override public void handleMessage(Message msg) { checkForUpdate(); if (isUpdate) { mThreadHandler.sendEmptyMessage(MSG_UPDATE_I NFO); } } };}/*** 模拟从服务器解析数据 */ private void checkForUpdate() { try {//模拟耗时 Thread.sleep(1200); mMainHandler.post(new Runnable() { @Override public void run() { String result = "实时更新中,当前股票行情:<font color='red'>%d</font>"; result = String.format(result, (int) (Math.r andom() * 5000 + 1000)); mTv.setText(Html.fromHtml(result)); } }); } catch (InterruptedException e) { e.printStackTrace(); } }@Override protected void onResume() { isUpdate = true;super.onResume(); mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO); }@Override protected void onPause() { super.onPause(); isUpdate = false; mThreadHandler.removeMessages(MSG_UPDATE_INFO); }@Override protected void onDestroy() { super.onDestroy(); mHandlerThread.quit(); mMainHandler.removeCallbacksAndMessages(null); }}

运行以上测试代码,将可以看到如下效果图(例子不太恰当,主要使用场景是在 handleMessage中执行耗时操作)

HandlerThread源码分析

官方源代码如下,是基于sdk23的,可以看到,只有一百多行代码而已。

  public class HandlerThread extends Thread {int mPriority; int mTid = -1; Looper mLooper; public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; }public HandlerThread(String name, int priority) { super(name); mPriority = priority; }/*** Call back method that can be explicitly overridden if nee ded to execute some * setup before Looper loops. */ protected void onLooperPrepared() { }@Override public void run() { mTid = Process.myTid(); Looper.prepare(); //持有锁机制来获得当前线程的Looper对象 synchronized (this) { mLooper = Looper.myLooper(); //发出通知,当前线程已经创建mLooper对象成功,这里主要是通知g etLooper方法中的wait notifyAll(); }//设置线程的优先级别 Process.setThreadPriority(mPriority); //这里默认是空方法的实现,我们可以重写这个方法来做一些线程开始之前 的准备,方便扩展 onLooperPrepared(); Looper.loop(); mTid = -1;}public Looper getLooper() { if (!isAlive()) { return null;}// 直到线程创建完Looper之后才能获得Looper对象,Looper未创建成功 ,阻塞 synchronized (this) { while (isAlive() && mLooper == null) { try {wait(); } catch (InterruptedException e) { } } }return mLooper; }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; }/*** Returns the identifier of this thread. See Process.myTid( ).*/ public int getThreadId() { return mTid; } }

1)首先我们先来看一下它的构造方法

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

有两个构造方法,一个参数的和两个参数的,name代表当前线程的名称,priority 为线程的优先级别

2)接着我们来看一下run()方法,在run方法里面我们 可以看到我们会初始化一个Looper,并设置线程的优 先级别

  public void run() { mTid = Process.myTid(); Looper.prepare(); //持有锁机制来获得当前线程的Looper对象 synchronized (this) { mLooper = Looper.myLooper(); //发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLo oper方法中的wait notifyAll(); }//设置线程的优先级别 Process.setThreadPriority(mPriority); //这里默认是空方法的实现,我们可以重写这个方法来做一些线程开始之前的准备 ,方便扩展 onLooperPrepared(); Looper.loop(); mTid = -1; }
  • 还记得我们前面我们说到使用HandlerThread的时候必须调用 start() 方 法,接着才可以将我们的HandlerThread和我们的handler绑定在一起吗?其实 原因就是我们是在 run() 方法才开始初始化我们的looper,而我们调用 HandlerThreadstart() 方法的时候,线程会交给虚拟机调度,由虚拟机 自动调用run方法
  mHandlerThread.start(); mThreadHandler = new Handler(mHandlerThread.getLooper()) { @Override public void handleMessage(Message msg) { checkForUpdate(); if(isUpdate){ mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);} } };
  • 这里我们为什么要使用锁机制和 notifyAll() ;,原因我们可以 从 getLooper() 方法中知道
  public Looper getLooper() { if (!isAlive()) { return null; }// 直到线程创建完Looper之后才能获得Looper对象,Looper未创建成功,阻塞 synchronized (this) { while (isAlive() && mLooper == null) { try {wait(); } catch (InterruptedException e) { } } }return mLooper; }

总结: 在获得mLooper对象的时候存在一个同步的问题,只有当线程创建成功并且 Looper对象也创建成功之后才能获得mLooper的值。这里等待方法wait和run方法 中的notifyAll方法共同完成同步问题。

3)接着我们来看一下quit方法和quitSafe方法

  //调用这个方法退出Looper消息循环,及退出线程 public boolean quit() { Looper looper = getLooper(); if (looper != null) {looper.quit(); return true; }return false; }//调用这个方法安全地退出线程 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) public boolean quitSafely() { Looper looper = getLooper(); if (looper != null) { looper.quitSafely(); return true; }return false;}

跟踪这两个方法容易知道只两个方法最终都会调用MessageQueuequit(boolean safe) 方法

  void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); }synchronized (this) { if (mQuitting) { return; }mQuitting = true; //安全退出调用这个方法 if (safe) { removeAllFutureMessagesLocked(); } else {//不安全退出调用这个方法 removeAllMessagesLocked(); }// We can assume mPtr != 0 because mQuitting was previou sly false.nativeWake(mPtr); } }

不安全的会调用 removeAllMessagesLocked(); 这个方法,我们来看这个方法是 怎样处理的,其实就是遍历Message链表,移除所有信息的回调,并重置为null。

  private void removeAllMessagesLocked() { Message p = mMessages; while (p != null) { Message n = p.next; p.recycleUnchecked(); p = n; }mMessages = null; }

安全地会调用 removeAllFutureMessagesLocked(); 这个方法,它会根据 Message.when这个属性,判断我们当前消息队列是否正在处理消息,没有正在处 理消息的话,直接移除所有回调,正在处理的话,等待该消息处理处理完毕再退出该循环。因此说 quitSafe() 是安全的,而 quit() 方法是不安全的,因为quit方 法不管是否正在处理消息,直接移除所有回调。

  private void removeAllFutureMessagesLocked() { final long now = SystemClock.uptimeMillis(); Message p = mMessages; if (p != null) { //判断当前队列中的消息是否正在处理这个消息,没有的话,直接移除所有 回调 if (p.when > now) { removeAllMessagesLocked(); } else {//正在处理的话,等待该消息处理处理完毕再退出该循环 Message n; for (;;) { n = p.next;if (n == null) { return; }if (n.when > now) { break; }p = n; }p.next = null; do {p = n; n = p.next; p.recycleUnchecked(); } while (n != null); } } }

文档笔记~

知识汇总的PDF相关内容后续GitHub更新,想冲击金三银四的小伙伴可以找找看看,欢迎star
顺手留下GitHub链接,需要获取相关面试等内容的可以自己去找
https://github.com/xiangjiana/Android-MS
更多完整项目下载。未完待续。源码。图文知识后续上传github。
可以点击关于我联系我获取

面试必问的一个知识点,关于HandlerThread的使用场景以及怎样使用 HandlerThread?相关推荐

  1. 我面试必问的一个问题

    阅读文本大概需要 1 分钟. 最近是跳槽的高峰,很多人应该都在准备面试,我知识星球有球友问我面试需要注意什么事项,其实面试需要注意的事项你可以网上搜索一大堆,那些事项会对你的面试多少有点帮助,但不会起 ...

  2. (100)详细描述一个你做过的项目, 面试必问(二十四)(第20天)

    (100)详细描述一个你做过的项目, 面试必问(二十四)(第20天) 1 文章目录 1)文章目录 2)FPGA初级课程介绍 3)FPGA初级课程架构 4)详细描述一个你做过的项目, 面试必问(二十四) ...

  3. linux驱动工程面试必问知识点

    linux内核原理面试必问(由易到难) 简单型 1:linux中内核空间及用户空间的区别?用户空间与内核通信方式有哪些? 2:linux中内存划分及如何使用?虚拟地址及物理地址的概念及彼此之间的转化, ...

  4. 互联网公司面试必问的Redis题目

    https://juejin.im/post/5b99d4bce51d450e7a24b66e#heading-0 Redis是一个非常火的非关系型数据库,火到什么程度呢?只要是一个互联网公司都会使用 ...

  5. 【Android面试】Android中高级开发面试必问,7年外包一飞冲天

    Andorid 开发在前两年也非常火热,但随着客户端开发招聘回归理性,行业已经越来越成熟,岗位招聘也就自然而然地变"卷"了.这一点,身为程序员老鸟的我深有体会. 年初,我就开始投递 ...

  6. 计算机网络八股文-面试必问

    搬运–面试必问计算机网络 原博客链接:https://www.nowcoder.com 每次面试问网络都还可以,整理了点资料,应付普通的问题没什么问题了. 除了字节的网络太为难人,其他公司都说回答的很 ...

  7. Java面试必问!javasocket服务端持久化

    前言 最近刷到了一句耐人寻味的话,"解决雪崩问题的最好办法是不发生雪崩". 不论是在硅谷互联网公司里还是在国内的互联网平台上,曾多次遇到过海量规模的交易瞬间吞噬平台的悲惨故事. 核 ...

  8. Android面试必问框架原理

    Android面试必问框架原理 volatile的实现原理 synchronized的实现原理 join方法实现原理 CAS无锁编程的原理 ReentrantLock的实现原理 AQS的大致实现思路 ...

  9. 看完946页“JAVA高级架构面试必问”,金九银十社招全拿下

    前言 我本科毕业后在老东家干了两年多,老东家算是一家"小公司"(毕竟这年头没有 BAT 或 TMD 的 title 都不好意思报出身),毕业这两年多我也没有在大厂待过,因此找坑的时 ...

最新文章

  1. 网络设备转发数据包的整个流程_网络工程师(33):路由转发工作原理
  2. Matplotlib实例教程(六)直方图
  3. storm集群部署和配置过程详解
  4. DLog-M有什么用
  5. Android从无知到有知——NO.6
  6. Merge k Sorted Lists
  7. 使用JavaParser进行java源码解析
  8. 2. 块和布局,小部件
  9. java 纯真ip数据库_纯真IP数据库格式读取方法(JAVA/PHP/Python)
  10. 如何使用最新Microsoft Edge打开Flash页面
  11. android 计时器函数,如何在Android中设置计时器
  12. Hello Qt(十六)——QT绘图实例-钟表
  13. html 文字自动转大写
  14. 罕见霜降胡杨照片,太美了!
  15. 如何获取宝宝取名软件注册码
  16. CGAL Arrangements and Their Applications: A Step-By-Step Guide
  17. jquery获取第一个子元素
  18. 单片机DAC输出方波简易实验
  19. [修改 Mysql5.7密码策略]Your password does not satisfy the current policy requirements
  20. tensorflow: 花卉分类

热门文章

  1. 自定义服务器怎么调98k,TP-Link TL-WR886N V2-V3虚拟服务器设置方法
  2. java编程手机gps定位_GPS 获取Gps定位信息的Android源码实例,通过这个JAVA 目,你可能学会GPS在 手机 238万源代码下载- www.pudn.com...
  3. 只用300小时,17岁高中生解开困扰数学家27年难题,因张益唐「入坑」数论
  4. !!!电脑上安装安卓系统模拟器的方法
  5. 每周积累|ARP欺骗攻击
  6. 关键字volatile有什么含意 并给出三个不同的例子
  7. 《Ext JS 6.2实战》节选——使用Sencha Cmd创建应用程序
  8. win10win11右键---新建文本文档消失的解决方案
  9. cloud foundry云原生开发工程师考试
  10. UG二次开发GRIP一键建立装配模型树