尊重原创,转载请注明出处:http://blog.csdn.net/a740169405/article/details/50257001
在线程成功执行后,HandlerThread创建了一个消息队列,用来接收其他线程发来的消息:
@Override
public void run() {
mTid = Process.myTid();
// 为当前线程创建Looper
Looper.prepare();
synchronized (this) {
// 获取当前线程Looper对象
mLooper = Looper.myLooper();
// 唤醒其他等待线程
notifyAll();
}
Process.setThreadPriority(mPriority);
// mLooper对象初始化完成后回调
onLooperPrepared();
// 开始循环读取消息队列里的消息
Looper.loop();
mTid = -1;
}
该方法调用了Looper.prepare();创建了一个消息队列。这样,该线程就能接收handler发送的消息了。
最后调用了Looper.loop();开始循环读取消息。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 创建线程,命名为"myHandlerThread"
HandlerThread handlerThread = new HandlerThread("myHandlerThread");
// 启动线程
handlerThread.start();
// 创建Handler,并指定使用HandlerThread的消息队列来处理消息
MyHandler myHandler = new MyHandler(handlerThread.getLooper());
// 发送一条空消息给消息队列
myHandler.obtainMessage().sendToTarget();
}
public static class MyHandler extends Handler {
public MyHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 收到消息后,打印出当前线程的名字
Log.e(TAG, "current Thread name : " + Thread.currentThread().getName());
}
}
我在主线程中初始化了一个HandlerThread线程,并启动了该线程。
向HandlerThread的消息队列发送了一条消息,消息收到后输出了当前线程的名字。
demo.chen.com.myapplication E/HandlerThreadActivity: current Thread name : myHandlerThread
后台输出的名字正是我创建线程的时候传递进去的。
通过上面的例子我们发现,向handlerThread发送的消息,是由HandlerThread线程来处理的。
大家注意这一段代码:
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
加锁是为了确保其他现成获取该线程的Looper时不为空。
我们再看看HandlerThread提供的获取Looper的方法:
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;
}
代码的意思很简单,如果Looper还未创建,则进入等待状态,直到Looper被创建。
我尝试写一个HandlerThread的子类来验证一下:
public static class MyHandlerThread extends HandlerThread {
public MyHandlerThread(String name) {
super(name);
}
@Override
public void run() {
try {
// 在线程启动后,初始化消息队列之前,sleep三秒
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 调用父类的run方法初始化消息队列
super.run();
}
@Override
public Looper getLooper() {
return super.getLooper();
}
}
逻辑很简单,重写run方法,在调用父类run方法进行Looper初始化之前让线程sleep三秒。
添加一些Log:
MyHandlerThread handlerThread = new MyHandlerThread("myHandlerThread");
// 线程启动前,先打个log记录当前时间
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Log.e(TAG, "current time = " + formatter.format(new Date()));
handlerThread.start();
Looper looper = handlerThread.getLooper();
// 在getLooper();之后打印log记录当前时间
Log.e(TAG, "get looper success, send message, time = " + formatter.format(new Date()));
MyHandler myHandler = new MyHandler(looper);
// 发送消息
myHandler.obtainMessage().sendToTarget();
再看看log:
E/HandlerThreadActivity: current time = 2015-12-11 08:45:03
E/HandlerThreadActivity: get looper success, send message, time = 2015-12-11 08:45:06
E/HandlerThreadActivity: current Thread name : myHandlerThread
从log中可以看出主线程等待了三秒,之所以加锁是为了防止在looper未被初始化之前,其他线程调用getLooper方法得到空对象。
一般我们是不需要重写HandlerThread类,只需要使用Handler对象向HandlerThread的消息队列发送消息,在handleMessage函数里处理消息,就可以了,且处理消息的线程是HandlerThread这个线程。
上面的例子中,我在消息队列初始化之前sleep了3秒,导致了主线程在getLooper的时候等待了3秒,也就是说有可能造成主线程ANR。
需要注意的是,一旦执行Looper.loop();线程便进入循环获取消息状态,也就是说线程不会自己停止,我们可以一直往线程发送消息,如果需要停止线程,只要调用HandlerThread对象的quit();或者quitSafely();函数,这两个函数其实只是调用了Looper对象的quit();或者quitSafely();函数:
HandlerThread的quit();函数:
public boolean quit() {
// 获取当前线程的Looper
Looper looper = getLooper();
if (looper != null) {
// 立即停止Looper的循环,不在处理未处理完的消息
looper.quit();
return true;
}
return false;
}
HandlerThread的quitSafely();函数:
public boolean quitSafely() {
// 获取当前线程的Looper
Looper looper = getLooper();
if (looper != null) {
// 打上需要停止循环的标志,等到消息都处理完以后,再推出循环
looper.quitSafely();
return true;
}
return false;
}
这两者的区别在于,调用quit();会直接终止消息队列的循环,如果队列中还有其他消息未处理,将不会被处理。
而调用quitSafely();函数则是给消息队列打上退出循环的标记,在所有消息处理完成以后,Looper自动退出循环,从而线程也就会结束。
1. HandlerThread类是google提供的一个,在线程内创建消息循环队列的线程API,让除了主线程以外的子线程也具有消息处理能力。
2. 使用时记得先调用HandlerThread的run方法启动线程
3. 在创建Handler时使用HandlerThread的Looper对象。
4. 确认所有任务都处理完成以后,记得调用HandlerThread推出函数,建议使用quitSafely();这样会等到所有消息都处理完后再推出线程。
应用:
HandlerThread在IntentService中应用到。
关于IntentService的项管内容,大家可以阅读我的另一片博客:Android IntentService的使用与源码解析