An Simple HandlerThread Example

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() 就是为了解决这两个线程的同步问题。

I Don't Want Your Money, I Want Aragaki Yui.