一.概述
什么是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.
我给大家翻译一下,大概的意思是说HandlerThread可以很方便的启动一个带有looper的线程,这个looper可以用来创建handler对象,同时别忘了start()方法也必须被调用。
首先来看看我们为什么要用HandlerThread,当我们在线程中实例化Handler的时候,必须保证当前线程中有Looper对象(主线程默认有Looper对象)。
为线程创建Looper对象的步骤如下:在线程的run()方法中先调用Looper.prepare()方法初始化,然后在run()方法最后调用Looper.loop()方法是Looper工作起来,这样我们就能保证当前线程已经创建好了Looper对象。那么我们实现Looper有没有更简单的方式呢?那就是HandlerThread。
二.实例
我们先看一个实例,效果如下:
这是子线程给主线程发送消息的一个例子
public class MainActivity extends Activity {
private TextView textivew;
int num = 0;
private MyThread thread;
private static Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textivew = (TextView) findViewById(R.id.textview);
thread = new MyThread();
thread.start();
}
public void send(View view) {
Message msg = Message.obtain();
msg.what = num;
thread.handler.sendMessage(msg);
textivew.setText("主线程向子线程发送" + num + "条消息");
num++;
}
class MyThread extends Thread {
Handler handler = null;
@Override
public void run() {
super.run();
Looper.prepare();
handler = new Handler() {
public void handleMessage(android.os.Message msg) {
Toast.makeText(MainActivity.this, "子线程接收到了" + msg.what + "条信息", Toast.LENGTH_SHORT).show();
}
};
Looper.loop();
}
}
}
下面我们看看如何使用HandlerThread
使用步骤:
1.创建一个HandlerThread,即创建了一个包含Looper的线程
HandlerThread handlerThread = new HandlerThread("lxn");
handlerThread.start(); //创建HandlerThread后一定要记得start()
HandlerThread的构造方法中传入一个字符串,代表线程名称。
2.获取HandlerThread的Looper对象
Looper looper = handlerThread.getLooper();
3.创建Handler,通过Looper初始化
Handler handler = new Handler(looper);
通过以上三步我们就成功创建HandlerThread。通过handler发送消息,就会在子线程中执行。
如果想让HandlerThread退出,则需要调用handlerThread.quit();。
下面我们用HandlerThread来实现上面的效果
public class MainActivity extends Activity {
private TextView textivew;
int num = 0;
private HandlerThread thread;
private static Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textivew = (TextView) findViewById(R.id.textview);
thread = new HandlerThread("lxn");
thread.start();
handler = new Handler(thread.getLooper()){
public void handleMessage(Message msg) {
Toast.makeText(MainActivity.this, "子线程接收到了"+msg.what+"条信息", Toast.LENGTH_SHORT).show();
};
};
}
public void send(View view) {
Message msg = Message.obtain();
msg.what = num;
handler.sendMessage(msg);
textivew.setText("主线程向子线程发送" + num + "条消息");
num++;
}
}
源码分析
public class HandlerThread extends Thread {
//当前线程优先级
int mPriority;
//线程id
int mTid = -1;
//Looper对象
Looper mLooper;
//使用默认优先级创建给定名称的线程
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
//使用指定的名称和优先级
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
...........
}
//重写此方法在Looper.loop之前做一些初始化动作
protected void onLooperPrepared() {
}
@Override
public void run() {
//获取当前进程id
mTid = Process.myTid();
//准备looper
Looper.prepare();
//同步机制获取当前Looper对象
synchronized (this) {
mLooper = Looper.myLooper();
//发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLooper方法中的wait
notifyAll();
}
//设置线程优先级
Process.setThreadPriority(mPriority);
//调用初始化方法,默认为空的
onLooperPrepared();
//Looper开始工作
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
//当前线程未启动则返回null
if (!isAlive()) {
return null;
}
synchronized (this) {
//线程已经启动,并且Looper还未创建,等待,直到收到Looper创建成功的通知
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
退出HandlerThread:
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是不安全的,因为这样会使Looper不再处理消息队列中剩下的消息,效率高点。
quitSafely是安全的,looper处理完消息后再退出,效率低点。
注意
Handler的创建应该放在HandlerThread调用start方法以后,因为在HandlerThread的run方法里才去创建Looper,否则会出现空指针