HandlerThread实例
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.text.Html;
import android.widget.TextView;
public class HandlerThreadActivity extends AppCompatActivity{
private TextView mTvServiceInfo;
private HandlerThread mCheckMsgThread;
private Handler mCheckMsgHandler;
private boolean isUpdateInfo;
private static final int MSG_UPDATE_INFO = 0x110;
//与UI线程管理的handler
private Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread_handler);
//创建后台线程
initBackThread();
mTvServiceInfo = (TextView) findViewById(R.id.id_textview);
}
@Override
protected void onResume(){
super.onResume();
//开始查询
isUpdateInfo = true;
mCheckMsgHandler.sendEmptyMessage(MSG_UPDATE_INFO);
}
@Override
protected void onPause(){
super.onPause();
//停止查询
isUpdateInfo = false;
mCheckMsgHandler.removeMessages(MSG_UPDATE_INFO);
}
@Override
protected void onDestroy(){
super.onDestroy();
//释放资源
mCheckMsgThread.quit();
}
private void initBackThread(){
mCheckMsgThread = new HandlerThread("check-message-coming");
mCheckMsgThread.start();
mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper()){
@Override
public void handleMessage(Message msg){
checkForUpdate();
if (isUpdateInfo){
mCheckMsgHandler.sendEmptyMessageDelayed(MSG_UPDATE_INFO, 1000);
}
}
};
}
/**
* 模拟从服务器解析数据
*/
private void checkForUpdate(){
try{
//模拟耗时
Thread.sleep(1000);
mHandler.post(new Runnable(){
@Override
public void run(){
String result = "实时更新中,当前大盘指数:<font color='red'>%d</font>";
result = String.format(result, (int) (Math.random() * 3000 + 1000));
mTvServiceInfo.setText(Html.fromHtml(result));
}
});
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
在onCreate中,去创建和启动了HandlerThread,并且关联了一个mCheckMsgHandler。然后我们分别在onResume和onPause中去开启和暂停我们的查询,最后在onDestory中去释放资源。
这样就实现了我们每隔5s去服务端查询最新的数据,然后更新我们的UI,当然我们这里通过Thread.sleep()模拟耗时,返回了一个随机数,大家可以很轻易的换成真正的数据接口。
HandlerThread 源码分析
我们是通过
mCheckMsgThread = new HandlerThread("check-message-coming");
mCheckMsgThread.start();
创建和启动的对象,那么查看HandlerThread的源码:
package android.os;
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
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;
}
}
看到了什么,其实我们就是初始化和启动了一个线程;然后我们看 run() 方法,可以看到该方法中调用了 Looper.prepare() , Loop.loop() 。
prepare() 中创建了一个Looper对象,并且把该对象放到了该线程范围内的变量中( sThreadLocal ),在 Looper 对象的构造过程中,初始化了一个 MessageQueue ,作为该 Looper 对象成员变量。
loop() 就开启了,不断的循环从 MessageQueue 中取消息处理了,当没有消息的时候会阻塞,有消息的到来的时候会唤醒。
接下来,我们创建了一个mCheckMsgHandler,是这么创建的:
mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper())
对应源码:
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;
}
mCheckMsgThread.getLooper() 返回的就是我们在 run 方法中创建的 mLooper 。
那么 Handler 的构造呢,其实就是在 Handler 中持有一个指向该 Looper.mQueue 对象,当 handler 调用 sendMessage 方法时,其实就是往该 mQueue 中去插入一个 message ,然后 Looper.loop() 就会取出执行。
如果你够细心你会发现, run 方法里面当mLooper创建完成后有个 notifyAll() , getLooper() 中有个 wait() ,这是为什么呢?因为的 mLooper 在一个线程中执行,而我们的 handler 是在 UI 线程初始化的,也就是说,我们必须等到 mLooper 创建完成,才能正确的返回 getLooper() 。 wait() , notify() 就是为了解决这两个线程的同步问题。