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是Android API提供的一个方便、便捷的类,使用它我们可以快速的创建一个带有Looper的线程。Looper可以用来创建Handler实例。注意:start()仍然必须被调用。
1.定义
一个Android 已封装好的轻量级异步类
2. 作用
实现多线程
在工作线程中执行任务,如 耗时任务
异步通信、消息传递
实现工作线程 & 主线程(UI线程)之间的通信,即:将工作线程的执行结果传递给主线程,从而在主线程中执行相关的UI操作
3. 优点
方便实现异步通信,即不需使用 “任务线程(如继承Thread类) + Handler”的复杂组合
4.代码实例
原料:
Button 点击按钮去执行请求随机数的任务
Textview 在界面上更新随机数
HandlerThread 创建Looper 与 Handler 绑定
预期效果 : 点击Button 在界面更新 一次随机数
public class MainActivity extends AppCompatActivity {
TextView tv;
Button btn;
//与Ui线程绑定的Handler实例。用来更新界面
private Handler mUiHandler = new Handler(){
public void handleMessage(Message msg) {
switch (msg.what) {
case 2:
tv.setText((String)msg.obj);
break;
default:
break;
}
};
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
btn = (Button) findViewById(R.id.btn);
MyhandlerThread = new HandlerThread("handlerThreadName"); // 创建HandlerThread实例
//开始运行线程
MyhandlerThread.start();
Looper loop = MyhandlerThread.getLooper();
//创建Handler与该线程绑定。
final Handler WorkerHandler = new Handler(loop) {
@Override
public void handleMessage(Message msg) {
Log.v("tag", Thread.currentThread().getName());
super.handleMessage(msg);
try {
Thread.sleep(1000); //等于 DownLoadApkFile
//模拟延时处理代表可以执行耗时操作 请求网络数据 ,IO 流
Message Mymsg = Message.obtain();
Mymsg .what=2;
Mymsg .obj=msg.obj;
mUiHandler.sendMessage(Mymsg);
//final String result=(String)msg1.obj; // 第二种方法 直接切换到handler的线程中更新
//mUiHandler.post(new Runnable() {
// @Override
//public void run() {
// tv.setText(result);
// }
// });
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
MyhandlerThread.quit();
// 结束线程,即停止线程的消息循环
}
}
以下是对于上述代码的解释
MyhandlerThread : 继承自Thread 作用创建实现了 Looper 和 Messagequeue
WorkerHandler : 在工作线程 在里边执行耗时方法 执行完成后 向mUiHandler 发送Message 。
mUiHandler :在主线程中创建的方法 用做更新UI。
执行结果很简单,就是 每点一次button 就会更新 一次随机数
HandlerThread 原理
步骤一 构造方法
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
// HandlerThread类有2个构造方法
// 区别在于:设置当前线程的优先级参数,即可自定义设置 or 使用默认优先级
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
}
HandlerThread(String name) 参数为线程名称,线程优先级Process.THREAD_PRIORITY_DEFAULT。
HandlerThread(String name, int priority),name为线程名称,priority为设置的线程优先级。
步骤二 Looper创建
HandlerThread其实还是一个线程,它跟普通线程有什么不同?
protected void onLooperPrepared() {
}
源码分析:此处调用的是父类(Thread类)的start(),最终回调HandlerThread的run()
@Override
public void run() {
// 1. 获得当前线程的id
mTid = Process.myTid();
// 2. 创建1个Looper对象 & MessageQueue对象
Looper.prepare();
synchronized (this) {
//创建Looper实例
mLooper = Looper.myLooper();//生成Looper =myLooper()是通过返回sThreadLocal.get() 获取线程里的looper对象
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();//空方法,在Looper创建完成后调用,可以自己重写逻辑
Looper.loop();//死循环,不断从MessageQueue中取出消息并且交给Handler处理
mTid = -1;
}
调用的 Looper.prepare();
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed)); //在threadLocal新建一个looper
}
步骤3:创建工作线程Handler & 复写handleMessage()
-
源码分析:handlerThread.getLooper()
-
作用:获得当前HandlerThread线程中的Looper对象
public Looper getLooper() { // 若线程不是存活的,则直接返回null if (!isAlive()) { return null; } // 若当前线程存活,再判断线程的成员变量mLooper是否为null // 直到线程创建完Looper对象后才能获得Looper对象,若Looper对象未创建成功,则阻塞 synchronized (this) { while (isAlive() && mLooper == null) { try { // 此处会调用wait方法去等待 wait(); } catch (InterruptedException e) { } } } // 上述步骤run()使用 持有锁机制 + notifyAll() 获得Looper对象后 // 则通知当前线程的wait()结束等待 & 跳出循环 // 最终getLooper()返回的是在run()中创建的mLooper对象 return mLooper; }
步骤四 退出方法 (quit 和quitsafely )
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;
}
quit和quitSafely都是退出HandlerThread的消息循环。其分别调用Looper的quit和quitSafely方法。
quit方法会将消息队列中的所有消息移除(延迟消息和非延迟消息)。
quitSafely会将消息队列所有的延迟消息移除,非延迟消息派发出去让Handler去处理。quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息
HandlerThread适合处理本地IO读写操作(数据库,文件),因为本地IO操作大多数的耗时属于毫秒级别,对于单线程 + 异步队列的形式 不会产生较大的阻塞。而网络操作相对比较耗时,容易阻塞后面的请求,因此在这个HandlerThread中不适合加入网络操作。