HandlerThread源码分析

HandlerThread是拿来做什么的呢?

我们知道Handler是用来异步更新UI的,更详细的说是用来做线程间的通信的,更新UI时是子线程UI主线程之间的通信。那么现在我们要是想子线程与子线程之间的通信要怎么做呢?当然说到底也是用Handler+Thread来完成,现在只不过Google官方很贴心的帮我们封装好了一个类HandlerThread

关于HandlerThreadLooper之间的故事可以参考这篇文章Android线程间通信的消息机制(Android开发艺术探索学习笔记),看完之后再来了解HandlerThread那就很容易了。

话不多说,直接上源码:

/**
 * Handy class for starting a new thread that has a looper. The looper can then be 
 * used to create handler classes. Note that start() must still be called.
 */
public class HandlerThread extends Thread {

}

HandlerThread继承自Thread,并且类上面的定义就直接告诉我们了,开启的HandlerThread会自带一个Looper
也就是说HandlerThread是自带Looper的线程。

那我们就去看run()

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

可以看到该方法中调用了Looper.prepare()Looper.loop()

Looper.prepare()中创建了一个Looper对象,并且把该对象放到了该线程范围内的变量中(sThreadLocal),在Looper对象的构造过程中,初始化了一个MessageQueue,作为该Looper对象成员变量。

Looper.loop()就开启了轮询,不断的循环从MessageQueue中取消息然后去处理,当没有消息的时候会阻塞,有消息到来的时候会唤醒。

看过上面推荐的文章,以上的分析你应该就了解了。

接下来,我们来看一个实例,代码如下:

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);

    }

    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();
        }

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //释放资源
        mCheckMsgThread.quit();
    }
}

布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingLeft="@dimen/activity_horizontal_margin"
                android:paddingRight="@dimen/activity_horizontal_margin"
                android:paddingTop="@dimen/activity_vertical_margin"
                android:paddingBottom="@dimen/activity_vertical_margin">

    <TextView
        android:id="@+id/id_textview"
        android:text="正在加载大盘指数..."
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</RelativeLayout>

可以看到我们在onCreate()中,去创建和启动了HandlerThread,并且关联了一个mCheckMsgHandler。然后我们分别在onResume()onPause()中去开启和暂停我们的查询,最后在onDestory()中去释放资源。

这样就实现了我们每隔5s去服务端查询最新的数据,然后更新我们的UI,当然我们这里通过Thread.sleep()模拟耗时,返回了一个随机数,大家可以很轻易的换成真正的数据接口。

在例子中,有一段代码是这样的:

        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);
                }
            }
        };

我们通过HandlerThreadgetLooper()得到mCheckMsgThread Looper,并作为参数传入Handler的构造函数,然后我们就为子线程mCheckMsgThread 创建了一个mCheckMsgHandler

这就来看一下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;
    }

run()里面当mLooper创建完成后有个notifyAll()getLooper()中有个wait(),这是为什么呢?

因为mLooper的创建是在子线程mCheckMsgThread 中执行,而我们的mCheckMsgHandler 是在主线程初始化的,也就是说,我们必须等到mLooper创建完成,才能正确的返回getLooper()notifyAll()wait()就是为了解决这两个线程的同步问题。

总结
HandlerThread类是一个专门处理Handler消息的线程,依次从Handler的队列中获取信息,逐个进行处理,保证安全,不会出现混乱引发的异常。HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,它有个Looper成员变量。

参考:Android HandlerThread 完全解析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值