HandlerThread 简介
Handler 必须要和 Looper 中结合使用,尤其在子线程中创建 Handler 的话,需要这样写:
/**
* @ 子线程写Handler+Looper
*/
private class LooperThread extends Thread {
private Handler mHandler;
@Override
public void run() {
Looper.prepare();
super.run();
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
Looper.loop();
}
}
非常繁琐,还需要手动调用Looper.prepare() 和 Looper.loop(),HandlerThread就是为了省去这些步骤而产生的,下面介绍一下HandlerThread的源码,一共160多行
HandlerThread源码
package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
/**
* 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 {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
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;
}
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
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;
}
/**
* @return a shared {@link Handler} associated with this thread
* @hide
*/
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
/**
* Quits the handler thread's looper.
* <p>
* Causes the handler thread's looper to terminate without processing any
* more messages in the message queue.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p class="note">
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*
* @see #quitSafely
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
/**
* Quits the handler thread's looper safely.
* <p>
* Causes the handler thread's looper to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* Pending delayed messages with due times in the future will not be delivered.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p>
* If the thread has not been started or has finished (that is if
* {@link #getLooper} returns null), then false is returned.
* Otherwise the looper is asked to quit and true is returned.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
/**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {
return mTid;
}
}
从源码中看出HandlerThread有以下特点
1、HandlerThread 是一个Thread,而且是一个包含 Looper 的 Thread,我们可以直接使用这个 Looper 创建 Handler;
2、HandlerThread创建完成必须调用start( )方法,就会去执行run( )方法;
3、也可以指定线程的优先级,注意使用的是 android.os.Process 而不是 java.lang.Thread 的优先级;
4、quit和quitSafely都是退出HandlerThread的消息循环。其分别调用Looper的quit和quitSafely方法。
quit方法会将消息队列中的所有消息移除(延迟消息和非延迟消息)。
quitSafely会将消息队列所有的延迟消息移除,非延迟消息派发出去让Handler去处理。quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息;
5、HandlerThread适合处理本地IO读写操作(数据库,文件),因为本地IO操作大多数的耗时属于毫秒级别,对于单线程 + 异步队列的形式 不会产生较大的阻塞。而网络操作相对比较耗时,容易阻塞后面的请求,因此在这个HandlerThread中不适合加入网络操作
举个例子
先上效果图,每次点击button,产生一个随机数显示在textview上
常规使用步骤
1、创建HandlerThread对象handlerThread
handlerThread = new HandlerThread("handlerthread");
2、启动handlerThread
handlerThread.start();
3、创建异步subHandler,绑定Looper(也可以使用Handler.Callback形式)
subHandler = new SubHandler(handlerThread.getLooper());
4、创建消息循环处理机制,异步subHandler发送数据到主线程Handler更新UI
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
try{
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg1 = new Message();
msg1.what = MSG_RESULT;
msg1.obj = Math.random();
mUiHandler.sendMessage(msg1);
}
这样整个Handler+Looper+MessageQueen+message循环消息处理机制就搭建完成
贴下整个Java代码,布局文件很简单就不贴了
package com.example.handlerthreaddemo;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
/**
* @ Introduce the method of using HandlerThread
* @ 8.7 2018
*/
public class HandlerThreadActivity extends AppCompatActivity {
private Button button;
private TextView textView;
private HandlerThread handlerThread;
private SubHandler subHandler;
private static int MSG_GET = 0;
private static int MSG_RESULT = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread);
textView = findViewById(R.id.textView);
button = findViewById(R.id.button);
handlerThread = new HandlerThread("handlerthread");
handlerThread.start();
subHandler = new SubHandler(handlerThread.getLooper());
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
subHandler.sendEmptyMessage(MSG_GET);
}
});
}
private class SubHandler extends Handler {
public SubHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
try{
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg1 = new Message();
msg1.what = MSG_RESULT;
msg1.obj = Math.random();
mUiHandler.sendMessage(msg1);
}
}
private Handler mUiHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 1:
String str = msg.obj.toString();
if(str != null){
textView.setText("num = "+str);
}
break;
}
}
};
@Override
protected void onDestroy() {
super.onDestroy();
handlerThread.quitSafely();
}
}