HandlerThread源码不多,分析源码之前首先要弄懂Handler,MessageQueue与Looper关系
android学习笔记----Handler的使用、内存泄漏、源码分析等一系列问题
关于HandlerThread源码分析可以见这里:
https://blog.csdn.net/lmj623565791/article/details/47079737
直接上笔记,来讲解一下上面博客的代码中的疑惑点:
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.util.Log;
import android.widget.TextView;
public class HandlerThreadActivity extends AppCompatActivity {
private TextView mTvServiceInfo;
private static final String TAG = "HandlerThreadActivity";
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);
}
private void initBackThread() {
mCheckMsgThread = new HandlerThread("check-message-coming");
mCheckMsgThread.start();
mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper()) {
// 执行回调的handlerMessage方法,看Looper在哪个线程,就在哪个线程执行
// 所以mCheckMsgHandler代表子线程的Handler
@Override
public void handleMessage(Message msg) {
checkForUpdate();
if (isUpdateInfo) { // 必须要此标志为才能及时停止消息
Log.d(TAG, "=======handleMessage: " + Thread.currentThread().getName());
mCheckMsgHandler.sendEmptyMessageDelayed(MSG_UPDATE_INFO, 1000);
}
}
};
}
/**
* 模拟从服务器解析数据
*/
private void checkForUpdate() {
try {
//模拟耗时
Thread.sleep(1000);
// 执行post方法看Handler对象绑定的哪个Looper,Looper属于哪个线程,这个Runnable对象就在哪个线程执行
// 所以mHandler代表主线程的Handler
mHandler.post(new Runnable() {
@Override
public void run() {
Log.d(TAG, "==========run: " + Thread.currentThread().getName());
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();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//释放资源
mCheckMsgThread.quit();
}
}
打印log,部分运行结果
......
批注: 执行回调的handlerMessage方法,看Looper在哪个线程,handler就属于哪个线程,就在哪个线程执行。执行post方法也看Handler对象绑定的哪个Looper,Looper属于哪个线程,handler属于对应线程,这个Runnable对象就在哪个线程执行,这里mHandler在主线程实例化,绑定了主线程的Looper,所以mHandler属于主线程,这个Runnable的run()方法就在main线程执行。
在这里mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper()){...}这个mCheckMsgThread是HandlerThread对象,所以getLooper出来的Looper对象是属于子线程的,所以mCheckMsgHandler是子线程的Handler对象,这个回调的handlerMessage方法是在子线程check-message-coming执行的。而调用post方法的Handler对象mHandler是在主线程实例化的,mHandler绑定了主线程的Looper,所以这个Runnable的run()方法就在main线程执行。这里不是start()开启新线程执行,而是直接执行run()方法,上一篇android学习笔记----Handler的使用、内存泄漏、源码分析等一系列问题已经解释过这个问题,源码写了的。
我们定义了标志位private boolean isUpdateInfo;是为了及时stop消息采用的,如果不要这个标志位,哪怕锁屏后执行的onPause()中mCheckMsgHandler.removeMessages(MSG_UPDATE_INFO);但是可能此时正好回调handleMessage,消息队列此时没有消息了,remove不了,此时已经锁屏,但handleMessage中又继续发送消息,不断循环了。
布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/id_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="正在加载大盘指数..." />
</RelativeLayout>
========================Talk is cheap, show me the code=======================