全面升级Android面试之HandlerThread面试题集

来源:互联网 发布:瑞典 二战 知乎 编辑:程序博客网 时间:2024/06/06 01:04

在此我们还是对之前介绍handler的原理和用法进行简单的总结以便于与HandlerThread进行区分

Handler 是跨线程的Message处理。负责把Message推送到MessageQueue和处理。

Looper 用来轮询MessageQueue,获取Message 发送给指定的Handler进行处理。

Looper 需要和线程绑定,绑定那个线程,Handler就会在那个线程处理Message

1.接着我们分析一下HandlerThread是用来做什么的?它是Handler还是Thread?

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

2.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释放,避免内存泄漏:

@Overrideprotected 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() {}@Overridepublic 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()这些方法。