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.