本文共 3843 字,大约阅读时间需要 12 分钟。
HandlerThread源码不多,分析源码之前首先要弄懂Handler,MessageQueue与Looper关系
关于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.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 = "实时更新中,当前大盘指数:%d"; 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()方法,上一篇已经解释过这个问题,源码写了的。
我们定义了标志位private boolean isUpdateInfo;是为了及时stop消息采用的,如果不要这个标志位,哪怕锁屏后执行的onPause()中mCheckMsgHandler.removeMessages(MSG_UPDATE_INFO);但是可能此时正好回调handleMessage,消息队列此时没有消息了,remove不了,此时已经锁屏,但handleMessage中又继续发送消息,不断循环了。
布局文件
========================Talk is cheap, show me the code=======================
转载地址:https://liuchenyang0515.blog.csdn.net/article/details/84633967 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!