android学习笔记----HandlerThread学习

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=======================

CSDN博客地址:https://blog.csdn.net/qq_34115899
原文地址:https://www.cnblogs.com/lcy0515/p/10807836.html