前言
前几天看到一道面试题: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释放,避免html" target="_blank">内存泄漏:
@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系统中,我们执行完耗时操作都要另外开启子线程来执行,执行完线程以后线程会自动销毁。想象一下如果我们在项目中经常要执行耗时操作,如果经常要开启线程,接着又销毁线程,这无疑是很消耗性能的?那有什么解决方法呢? 使用线程池 使用HandlerThread 本篇文章主要讲解一下问题 HandlerThread的使用场景以及怎样使用HandlerThread? HandlerThre
Thread,Looper和Handler的关系 与Windows系统一样,Android也是消息驱动型的系统。引用一下消息驱动机制的四要素: 接收消息的“消息队列” 阻塞式地从消息队列中接收消息并进行处理的“线程” 可发送的“消息的格式” “消息发送函数” 与之对应,Android中的实现对应了 接收消息的“消息队列” ——【MessageQueue】 阻塞式地从消息队列中接收消息并进行处理的“
本文向大家介绍详解Java中Thread 和Runnable区别,包括了详解Java中Thread 和Runnable区别的使用技巧和注意事项,需要的朋友参考一下 Thread 和Runnable 关系 Thread类是接口Runnable的一个实现类。 源码分析 Thread Threa类运行的时候调用start()方法,源代码如下: 调用start()方法,实际运行的是start0方法,方法声
本文向大家介绍Android HandlerThread的使用及原理详解,包括了Android HandlerThread的使用及原理详解的使用技巧和注意事项,需要的朋友参考一下 一、HandlerThread的含义 HandlerThread能够新建拥有Looper的线程。这个Looper能够用来新建其他的Handler。(线程中的Looper)需要注意的是,新建的时候需要被回调。 二、Hand
本文向大家介绍Android消息处理机制Looper和Handler详解,包括了Android消息处理机制Looper和Handler详解的使用技巧和注意事项,需要的朋友参考一下 Android系统的消息队列和消息循环都是针对具体线程的,一个线程可以存在(当然也可以不存在)一个消息队列和一个消 息循环(Looper),特定线程的消息只能分发给本线程,不能进行跨线程,跨进程通讯。但是创建的工作线程默
本文向大家介绍Android Handler的详解及实例,包括了Android Handler的详解及实例的使用技巧和注意事项,需要的朋友参考一下 Android Handler的详解 Handler我们常常用于通知主线程做相对应的操作,但是如果使用不但的话就会造成内存泄露,所以记录写正确的Handler写法。 像上面的代码片段,就会存在内存泄露的风险,因为handler占着Acitvity的引用