HandlerThread实例
在上一遍中文章Android消息处理机制—Handler、Message、Looper源码原理解析中我们学习了Looper、Handler、Message之间的关系,在子线程中创建Handler的过程稍显复杂,有没有一种更简单的办法呢,答案是肯定的,其实Android已经为我们封装了一个Handler、Looper的结合体——HandlerThread,我们来看一个HandlerThread的实例:
public class MainActivity extends Activity {
private HandlerThread mHandlerThread;
//工作在子线程中的Handler
private Handler mSecondHandler;
//工作在UI线程中的Handler
private Handler mUIHandler;
private int MESSAGE_WORK = 0X01;
private int MESSAGE_DONE = 0X02;
private Button mButton;
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton = (Button) findViewById(R.id.send);
mTextView = (TextView) findViewById(R.id.tx);
mUIHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
//UI线程中的Handler收到后信息更新界面
super.handleMessage(msg);
if (msg.what == MESSAGE_DONE) {
mTextView.setText("the number is : " + msg.arg1);
}
}
};
mHandlerThread = new HandlerThread("test");
//必须调用
mHandlerThread.start();
mSecondHandler = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
//工作在子线程中
super.handleMessage(msg);
try {
//模拟耗时操作
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//耗时操作完成后通过UIHandler通知UI线程更新界面
Message done = new Message();
done.what = MESSAGE_DONE;
Random rand = new Random();
done.arg1 = rand.nextInt(100);
mUIHandler.sendMessage(done);
}
}
};
//发送消息给子线程中的Handler
mSecondHandler.sendEmptyMessage(0x123);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mSecondHandler.sendEmptyMessage(MESSAGE_WORK);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
//不再使用时释放Looper
mHandlerThread.quit();
}
}
在上面的例子中,我们在子线程中使用创建Handler来处理消息时只需创建一个HandlerThread,并在创建子线程Handler的时候传入HandlerThread.getLooper() ,不再需要调用Looper.prepare()和Looper.loop(),甚至不用创建Thread,看上去是不是简单多了,接下来看看Handlerthread是怎样工作的。
源码分析
其实HandlerThread的源码只有200行不到:
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
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;
}
}
从以上源码中可以知道,其实HandlerThread其实是一个Thread,我们通过它的构造函数指定HandlerThread的名字,设置线程的优先级,默认情况的线程级别是0。既然是继承Thread类,那最重要的肯定是重写run()方法了,在HandlerThread的run()中首先通过Looper.prepare()来获取创建Looper实例,所以我们要在创建Handler之前要调用start()方法,然后回调run()去创建Looper对象,在run()方法中通过线程同步去给当前成员变量mLooper赋值,当mLooper = Looper.myLooper()完成之后,通过notifyAll()通知mLooper已经创建完成,然后getLooper()时才能获取到Looper对象,否则getLooper()这个方法就会一直wait(),直到Looper被初始化。此外,我们可以通过重写onLooperPrepared()这个方法在Looper.looper()开始前执行我们需要的一些操作,然后run()中调用Looper.loop(),这样Looper就开始工作了。
通过以上的分析可知,原来HandlerThread已经为我们创建好了Looper对象,我们只需要在创建Handler时通过getLooper()方法将Looper实例传入即可,这样一套完整的消息处理机制就完成了,当我们不在需要HandlerThread时记得通过下面两个方法Looper循环:
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()会在清空消息之前继续派发所有非延迟消息,而quit()则会立即清空所有的非延迟消息和延迟消息(通过sendMessageDelayed或通过postDelayed等方法发送的为延迟消息)。