handlerthread
handlerthread是什么
官方解释
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.
方便我们创建一个拥有looper的线程
HandlerThread继承自Thread,因此HandlerThread其实就是一个线程。
线程开启时也就是run方法运行起来后,线程同时创建一个含有消息队列的looper,并对外提供自己这个对象的get方法,这就是和普通的Thread不一样的地方。可用于多个耗时任务要串行执行。
如果对handler不熟的话,可以先看这个Handler介绍
使用流程
- 实例对象,参数为线程名字
HandlerThread handlerThread = new HandlerThread("handlerThread");
- 启动线程
handlerThread.start();
- 实例主线程的Handler,参数为HandlerThread内部的一个looper.
Handler handler = new Handler(handlerThread.getLooper()) {
@Override
public void handlemessage(Message msg) {
super.handleMessage(msg);
}
};
看个简单的例子
里面打了挺多的注释,Log日志也用序号标明了顺序。这里模拟的情况是我们在子线程下载东西,然后和主线程之间进行通信。主线程知道了下载开始和下载结束的时间,也就能及时改变界面UI。
首先是DownloadThread
类,继承于HandlerThread
,用于下载。
public class DownloadThread extends HandlerThread{
private static final String TAG = "DownloadThread";
public static final int TYPE_START = 2;//通知主线程任务开始
public static final int TYPE_FINISHED = 3;//通知主线程任务结束
private Handler mUIHandler;//主线程的Handler
public DownloadThread(String name) {
super(name);
}
/*
* 执行初始化任务
* */
@Override
protected void onLooperPrepared() {
Log.e(TAG, "onLooperPrepared: 1.Download线程开始准备");
super.onLooperPrepared();
}
//注入主线程Handler
public void setUIHandler(Handler UIhandler) {
mUIHandler = UIhandler;
Log.e(TAG, "setUIHandler: 2.主线程的handler传入到Download线程");
}
//Download线程开始下载
public void startDownload() {
Log.e(TAG, "startDownload: 3.通知主线程,此时Download线程开始下载");
mUIHandler.sendemptyMessage(TYPE_START);
//模拟下载
Log.e(TAG, "startDownload: 5.Download线程下载中...");
SystemClock.sleep(2000);
Log.e(TAG, "startDownload: 6.通知主线程,此时Download线程下载完成");
mUIHandler.sendEmptyMessage(TYPE_FINISHED);
}
}
然后是MainActivity
部分。
public class MainActivity extends APPCompatActivity {
private static final String TAG = "MainActivity";
private DownloadThread mHandlerThread;//子线程
private Handler mUIhandler;//主线程的Handler
@Override
protected void onCreate(Bundle savedinstanceState) {
super.onCreate(savedInstanceState);
setcontentView(R.layout.activity_main);
//初始化,参数为线程的名字
mHandlerThread = new DownloadThread("mHandlerThread");
//调用start方法启动线程
mHandlerThread.start();
//初始化Handler,传递mHandlerThread内部的一个looper
mUIhandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
//判断mHandlerThread里传来的msg,根据msg进行主页面的UI更改
switch (msg.what) {
case DownloadThread.TYPE_START:
//不是在这里更改UI哦,只是说在这个时间,你可以去做更改UI这件事情,改UI还是得在主线程。
Log.e(TAG, "4.主线程知道Download线程开始下载了...这时候可以更改主界面UI");
break;
case DownloadThread.TYPE_FINISHED:
Log.e(TAG, "7.主线程知道Download线程下载完成了...这时候可以更改主界面UI,收工");
break;
default:
break;
}
super.handleMessage(msg);
}
};
//子线程注入主线程的mUIhandler,可以在子线程执行任务的时候,随时发送消息回来主线程
mHandlerThread.setUIHandler(mUIhandler);
//子线程开始下载
mHandlerThread.startDownload();
}
@Override
protected void onDestroy() {
//有2种退出方式
mHandlerThread.quit();
//mHandlerThread.quitSafely(); 需要API>=18
super.onDestroy();
}
}
运行的Log日志如下
注意
这个使用的顺序是不能更改的!!!,因为如果不先让子线程start起来,那么创建主线程的handler的参数getLooper是获取不到的,这一点可以看源码就清楚。
完整的源码介绍可以参考这一篇
public Looper getLooper() {
if (!isAlive()) {
return null;
}
synchronized (this) {
while (isAlive() && mLooper == null) {//循环等待
try {
wait();//mLooper为空的话,我们getLooper不到的,必须先给mLooper赋值
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
@Override
public void run() {
mTid = Process.myTid();
looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();//这里赋值了,调用start() 后就会执行此方法
notifyAll();
}
Process.setThreadpriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
感谢
https://blog.csdn.net/u011240877/article/details/72905631
https://blog.csdn.net/userzhanghao123/article/details/51683403
相关阅读
Android多线程:HandlerThread详细使用手册
前言 多线程的应用在Android开发中是非常常见的,常用方法主要有:继承Thread类 实现Runnable接口 Handler AsyncTask HandlerThread
Android HandlerThread使用介绍以及源码解析
1. 前言 首先,看一下官方对HandlerThread的解释: Handy class for starting a new thread that has a looper. The looper can th