前几天看到一道面试题: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)segmentfault
仍是先来看看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("收到消息"); } };
而后再新建一个子线程来发送消息:ide
new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000);//模拟耗时操做 handler.sendEmptyMessage(0); } catch (InterruptedException e) { e.printStackTrace(); } } }).start();
最后必定不要忘了在onDestroy释放,避免内存泄漏:oop
@Override protected void onDestroy() { super.onDestroy(); mHandlerThread.quit(); }
执行结果很简单,就是在控制台打印字符串:收到消息post
整个的使用过程咱们根本不用去关心Handler相关的东西,只须要发送消息,处理消息,Looper相关的东西交给它本身去处理,仍是来看看源码它是怎么实现的,先看构造方法:ui
public class HandlerThread extends Thread {}
HandlerThread其实仍是一个线程,它跟普通线程有什么不一样?this
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方法:.net
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()这些方法。