HandlerThread 是一个包含 Looper 的 Thread,我们可以直接使用这个 Looper 创建 Handler。对Handler机制不甚了解的朋友,可以去阅读我的另一篇博文:Handler机制。
HandlerThread源码:
import android.os.Looper;
import android.os.Process;
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
//设置线程名称和指定线程的优先级
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
// 子类需要重写的方法,在这里做一些执行前的初始化工作
protected void onLooperPrepared() {}
//获取当前线程的 Looper
//如果线程不是正常运行的就返回 null
//如果线程启动后,Looper 还没创建,就 wait() 等待 创建 Looper 后 notify
public Looper getLooper() {
if (!isAlive()) {
return null;
}
synchronized (this) {
while (isAlive() && mLooper == null) { //循环等待
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
//调用 start() 后就会执行的 run()
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare(); //帮我们创建了 Looepr
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll(); //Looper 已经创建,唤醒阻塞再获取 Looper 的线程
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop(); //开始循环
mTid = -1;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
public int getThreadId() {
return mTid;
}
}
从源码中可以看出,HandlerThread继承于Thread,当调用HandlerThread实例的start()方法时,就是启动一个线程,run() 方法里的逻辑代码就会被执行。
public void run() {
mTid = Process.myTid();
Looper.prepare(); //帮我们创建了 Looepr
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll(); //Looper 已经创建,唤醒阻塞再获取 Looper 的线程
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop(); //开始循环
mTid = -1;
}
run()函数中。最关键的部分是获取本线程的looper,并调用可能被子类重载的onLooperPrepared()方法。
为了便于理解,利用HandlerThread,我写了一个实现多个下载任务的demo。
继承于HandlerThread的DownloadThread
package com.zrp.myhandlerthread;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.text.format.DateUtils;
import java.util.Arrays;
import java.util.List;
public class DownloadThread extends HandlerThread implements Handler.Callback {
private final String TAG = this.getClass().getSimpleName();
private final String KEY_URL = "url";
public static final int TYPE_START = 1;
public static final int TYPE_FINISHED = 2;
private Handler mWorkerHandler;
private Handler mUIHandler;
private List<String> mDownloadUrlList;
public DownloadThread(final String name) {
super(name);
}
@Override
protected void onLooperPrepared() { //重载HandlerThread的onLooperPrepared()方法,执行初始化任务
super.onLooperPrepared();
mWorkerHandler = new Handler(getLooper(), this); //使用子线程中的 Looper
if (mUIHandler == null) {
throw new IllegalArgumentException("Not set UIHandler!");
}
//将接收到的任务消息挨个添加到消息队列中
for (String url : mDownloadUrlList) {
Message message = mWorkerHandler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString(KEY_URL, url);
message.setData(bundle);
mWorkerHandler.sendMessage(message);
}
}
public void setDownloadUrls(String... urls) {
mDownloadUrlList = Arrays.asList(urls);
}
public Handler getUIHandler() {
return mUIHandler;
}
//注入主线程 Handler
public DownloadThread setUIHandler(final Handler UIHandler) {
mUIHandler = UIHandler;
return this;
}
/**
* 子线程中执行任务,完成后发送消息到主线程
*
* @param msg
* @return
*/
@Override
public boolean handleMessage(final Message msg) {
if (msg == null || msg.getData() == null) {
return false;
}
String url = (String) msg.getData().get(KEY_URL);
//下载开始,通知主线程
Message startMsg = mUIHandler.obtainMessage(TYPE_START, "\n 开始下载 @" + System.currentTimeMillis() + "\n" + url);
mUIHandler.sendMessage(startMsg);
SystemClock.sleep(2000); //模拟下载
//下载完成,通知主线程
Message finishMsg = mUIHandler.obtainMessage(TYPE_FINISHED, "\n 下载完成 @" + System.currentTimeMillis() + "\n" + url);
mUIHandler.sendMessage(finishMsg);
return true;
}
@Override
public boolean quitSafely() {
mUIHandler = null;
return super.quitSafely();
}
}
MainActivity:
package com.zrp.myhandlerthread;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements Handler.Callback{
TextView mTvStartMsg;
TextView mTvFinishMsg;
Button mBtnStartDownload;
private Handler mUIHandler;
private DownloadThread mDownloadThread;
@Override
protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
init();
}
private void initViews() {
mTvStartMsg = (TextView) findViewById(R.id.tv_start_msg);
mTvFinishMsg = (TextView) findViewById(R.id.tv_finish_msg);
mBtnStartDownload = (Button) findViewById(R.id.btn_start_download);
}
private void init() {
mUIHandler = new Handler(this);
mDownloadThread = new DownloadThread("DownloadThread");
mDownloadThread.setUIHandler(mUIHandler);
mDownloadThread.setDownloadUrls("http://pan.baidu.com/s/1qYc3EDQ",
"http://bbs.005.tv/thread-589833-1-1.html",
"http://list.youku.com/show/id_zc51e1d547a5b11e2a19e.html?");
}
public void startDownload(View v) {
mDownloadThread.start();
mBtnStartDownload.setText("正在下载");
mBtnStartDownload.setEnabled(false);
}
//主线程中的 Handler 处理消息的方法
@Override
public boolean handleMessage(final Message msg) {
switch (msg.what) {
case DownloadThread.TYPE_FINISHED:
mTvFinishMsg.setText(mTvFinishMsg.getText().toString() + "\n " + msg.obj);
mBtnStartDownload.setText("下载完成");
break;
case DownloadThread.TYPE_START:
mTvStartMsg.setText(mTvStartMsg.getText().toString() + "\n " + msg.obj);
break;
}
return true;
}
}
MainActivity的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="8dp">
<TextView
android:id="@+id/tv_start_msg"
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="下载开始信息"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/colorAccent"/>
<TextView
android:id="@+id/tv_finish_msg"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="8dp"
android:text="下载完成信息"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/colorAccent"/>
<Button
android:id="@+id/btn_start_download"
android:onClick="startDownload"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="开始下载"/>
</LinearLayout>