HandlerThread 使用及分析

HandlerThread

先看 HandlerThread 的成员变量,源码如下:

public class HandlerThread extends Thread {
    // 线程优先级
    int mPriority;
    // 线程 ID
    int mTid = -1;
    // 跟线程绑定的 Looper
    Looper mLooper;
    // 跟线程绑定的 Handler
    Handler mHandler;
}

接着,我们看一下 HandlerThread 的构造函数:

// 构造方法,传入线程名称
public HandlerThread(String name) {
    super(name);
    mPriority = Process.THREAD_PRIORITY_DEFAULT;
}

// 构造方法,传入线程名称和线程优先级
public HandlerThread(String name, int priority) {
    super(name);
    mPriority = priority;
}

共有两个构造方法,入参 name 表示线程名称,入参 priority 表示线程的优先级。

接着,有一个模板方法,供扩展用,在 Looper 工作之前会回调,如下:

// 子类覆写,Looper.loop() 之前会回调
protected void onLooperPrepared() {
}

默认是空实现,供子类实现逻辑。

因为 HandlerThreadThread 的子类,所以我们重点看一下 run 方法:

@Override
public void run() {
    mTid = Process.myTid();
    // 创建 Looper
    Looper.prepare();
    // 持有锁机制来获得当前线程的Looper对象
    synchronized (this) {
        mLooper = Looper.myLooper();
        // 唤醒,当前线程已经创建mLooper对象成功,这里主要是通知getLooper方法中的wait
        notifyAll();
    }
    // 设置线程的优先级
    Process.setThreadPriority(mPriority);
    // 这里默认是空方法的实现,我们可以重写这个方法来做一些 Looper工作之前的准备,方便扩展
    onLooperPrepared();
    // Looper 开始工作
    Looper.loop();
    mTid = -1;
}

Android 系统中,我们执行耗时操作都要另外开启子线程来执行,执行完线程以后线程会自动销毁。所以当我们经常需要异步处理任务时,需要反复开启和销毁线程,非常消耗性能。而 HandlerThread 的工作机制就是 Handler 的工作机制,运行了 run 方法,Looper 就进入死循环,线程也就不会销毁,我们可以通过 HandlerThread 来串行执行多个不同的异步任务。

通过源码可知,HandlerThread 是自带 LooperThread ,那么怎样获取当前的 Looper 呢?

// 获取当前的 Looper
public Looper getLooper() {
        // 线程没有启动或者已经死亡时返回 null
        if (!isAlive()) {
            return null;
        }

        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            // 线程已经启动但是 Looper 对象还没有创建完成
            while (isAlive() && mLooper == null) {
                try {
                    // 等待
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    } 

上述分析说到,HandlerThread 开启之后不会自动销毁,那肯定就有主动销毁的方法,如下:

// 退出 Looper 循环,把当前消息队列中的所有消息都抛弃
public boolean quit() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quit();
        return true;
    }
    return false;
}

// 退出 Looper 循环,它会让消息队列中的非延迟消息继续得到处理,只抛弃延时消息
public boolean quitSafely() {
    Looper looper = getLooper();
    if (looper != null) {
        looper.quitSafely();
        return true;
    }
    return false;
}

还有一些其他的方法,如下:

// 获取线程绑定的 Handler
public Handler getThreadHandler() {
    if (mHandler == null) {
        mHandler = new Handler(getLooper());
    }
    return mHandler;
}

// 返回线程ID
public int getThreadId() {
    return mTid;
}

HandlerThread 的源码就是这么多,接下来我们看一下 HandlerThread 是怎样使用的。

基本使用方式

步骤一: 创建 HandlerThread 实例

mHandlerThread = new HandlerThread("test");

步骤二: 启动线程

mHandlerThread.start();

步骤三: 创建子线程 Handler

mThreadHandler = new Handler(mHandlerThread.getLooper()) {
        @Override
        public void handleMessage(Message msg) {
            Log.d("HandlerThreadActivity", Thread.currentThread().getName());

            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                mUIHandler.sendMessage(mUIHandler.obtainMessage(1, "success"));
            }
        }
    };

注意:子线程的 Handler 创建时需要用到 HandlerThreadLooper ,这样才能保证 Handler 发送的消息在子线程做处理。

步骤四: 销毁线程

mHandlerThread.quit();

完整的使用案例

public class HandlerThreadActivity extends AppCompatActivity implements View.OnClickListener {

    TextView mStartThread;

    HandlerThread mHandlerThread;

    private Handler mThreadHandler;

    private UIHandler mUIHandler = new UIHandler(this);

    private static class UIHandler extends Handler {

        private WeakReference<HandlerThreadActivity> mWeakReference;

        public UIHandler(HandlerThreadActivity activity) {
            mWeakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            if (mWeakReference.get() != null) {
                Log.d("HandlerThreadActivity", Thread.currentThread().getName());
                Toast.makeText(mWeakReference.get(), msg.obj.toString(), Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler_thread);
        mStartThread = findViewById(R.id.tv_send_message);
        mStartThread.setOnClickListener(this);
        mHandlerThread = new HandlerThread("test");
        mHandlerThread.start();

        mThreadHandler = new Handler(mHandlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                Log.d("HandlerThreadActivity", Thread.currentThread().getName());

                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    mUIHandler.sendMessage(mUIHandler.obtainMessage(1, "success"));
                }
            }
        };
    }

    @Override
    public void onClick(View v) {
        mThreadHandler.sendEmptyMessage(1);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandlerThread.quit();

    }
}

主要是模拟子线程处理耗时操作,案例中在主线程通过子线程的 Handler 发送了一个空消息,子线程通过回调休眠了两秒钟后,通过主线程的 Handler 发送一个成功的消息,最后显示了一个成功的提示。