HandlerThread 是一个包含 Looper 的 Thread,我们可以直接使用这个 Looper 创建 Handler。

 1.HandlerThread 源码

 public class HandlerThread extends Thread {
int mPriority;
int mTid = -;
Looper mLooper; public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
} //也可以指定线程的优先级,注意使用的是 android.os.Process 而不是 java.lang.Thread 的优先级!
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 = -;
} 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,创建后别忘了调用 start()。
②在 run() 方法中创建了 Looper,调用 onLooperPrepared 后开启了循环
③我们要做的就是在子类中重写 onLooperPrepared,做一些初始化工作
④在创建 HandlerThread 时可以指定优先级,注意这里的参数是 Process.XXX 而不是 Thread.XXX

2.HandlerThread 的使用场景
我们知道,HandlerThread 所做的就是在新开的子线程中创建了 Looper,那它的使用场景就是 Thread + Looper 使用场景的结合,即:在子线程中执行耗时的、可能有多个任务的操作。
比如说多个网络请求操作,或者多文件 I/O 等等。
使用 HandlerThread 的典型例子就是 IntentService,我们下篇文章介绍它。

3.举个栗子
我们写一个使用 HandlerThread 实现子线程完成多个下载任务的 demo。
先创建一个 HandlerThread 子类,它有两个 Handler 类型的成员变量,一个是用于在子线程传递、执行任务,另一个用于外部传入,在主线程显示下载状态:

 /**
* 继承 HandlerThread 模拟下载线程
*/
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 = ;
public static final int TYPE_FINISHED = ; private Handler mWorkerHandler;
private Handler mUIHandler;
private List<String> mDownloadUrlList; public DownloadThread(final String name) {
super(name);
} @Override
protected void 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 开始下载 @" + DateUtils.getCurrentTime() + "\n" + url);
mUIHandler.sendMessage(startMsg); SystemClock.sleep(); //模拟下载 //下载完成,通知主线程
Message finishMsg = mUIHandler.obtainMessage(TYPE_FINISHED, "\n 下载完成 @" + DateUtils.getCurrentTime() + "\n" + url);
mUIHandler.sendMessage(finishMsg); return true;
} @Override
public boolean quitSafely() {
mUIHandler = null;
return super.quitSafely();
}
}

可以看到,DownloadThread 中做了以下工作:

创建一个子线程 Handler
然后在 onLooperPrepared()中初始化 Handler,使用的是 HandlerThread 创建的 Looper
同时将外部传入的下载 url 以 Message 的方式发送到子线程中的 MessageQueue 中
这样当调用 DownloadThread.start() 时,子线程中的 Looper 开始工作,会按顺序取出消息队列中的队列处理,然后调用子线程的 Handler 处理
也就是上面的 handleMessage() 方法,在这个方法中进行耗时任务
然后通过 mUIHandler 将下载状态信息传递到主线程

调用 Activity 的代码:

 public class HandlerThreadActivity extends AppCompatActivity implements Handler.Callback {

     @BindView(R.id.tv_start_msg)
TextView mTvStartMsg;
@BindView(R.id.tv_finish_msg)
TextView mTvFinishMsg;
@BindView(R.id.btn_start_download)
Button mBtnStartDownload; private Handler mUIHandler;
private DownloadThread mDownloadThread; @Override
protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread_test);
ButterKnife.bind(this);
init();
} private void init() {
mUIHandler = new Handler(this);
mDownloadThread = new 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?");
} @OnClick(R.id.btn_start_download)
public void startDownload() {
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);
break;
case DownloadThread.TYPE_START:
mTvStartMsg.setText(mTvStartMsg.getText().toString() + "\n " + msg.obj);
break;
}
return true;
}
}

HandlerThread使用的更多相关文章

  1. Android HandlerThread 总结使用

    转载请标明出处:http://www.cnblogs.com/zhaoyanjun/p/6062880.html 本文出自[赵彦军的博客] 前言 以前我在 [Android Handler.Loop ...

  2. HandlerThread 创建一个异步的后台线程

    使用HandlerThread几大优点: 1.制作一个后台异步线程,需要的时候就可以丢一个任务给它,使用比较灵活; 2.Android系统提供的,使用简单方便,内部自己封装了Looper+Handle ...

  3. 关于HandlerThread的分析

    Android中的Thread没有对java中的Thread做任何封装,而Android提供了一个遍历方法HandlerThread,他继承于Thread,实现了对遍历系统的一些封装,下面研究一下Ha ...

  4. Android HandlerThread 的使用及其Demo (转)

    转自http://www.cnblogs.com/hnrainll/p/3597246.html 介绍 首先我们来看看为什么我们要使用HandlerThread?在我们的应用程序当中为了实现同时完成多 ...

  5. HandlerThread和IntentService

    HandlerThread 为什么要使用HandlerThread? 我们经常使用的Handler来处理消息,其中使用Looper来对消息队列进行轮询,并且默认是发生在主线程中,这可能会引起UI线程的 ...

  6. HandlerThread源码分析

    其实原本HandlerThread的分析不应该单独开一篇博客的,应该在讲消息机制的那一片中一起分析. 但当时忘记了,而且今天第一次用MarkDown写博客,有点上瘾,就再来一篇,权当滥竽充数过过手瘾. ...

  7. HandlerThread

    一.概念     1.Android中Handler的使用,一般都在UI主线程中执行,因此在Handler接收消息后,处理消息时,不能做一些很耗时的操作,否则将出现ANR错误. 2.HandlerTh ...

  8. 【Android】用HandlerThread模拟AsyncTask功能(ThreadTask)

    前言 AsyncTask是个好东西,能处理绝大多数应用线程和更新UI的任务,由于其内部使用了静态线程池,如果你有一堆异步任务(例如全局定时更新数据.同一个Activity中多个AsyncTask同时执 ...

  9. HandlerThread 用法

    HandlerThread最大的优势在于引入MessageQueue概念,可以进行多任务队列管理. HandlerThread背后只有一个线程,所以任务是串行依次执行的.串行相对于并行来说更安全,各任 ...

  10. Android HandlerThread 的使用及其Demo

    今天我们一起来学习下一个Android中比较简单的类HandlerThread,虽然它的初始化有点小麻烦. 介绍 首先我们来看看为什么我们要使用HandlerThread?在我们的应用程序当中为了实现 ...

随机推荐

  1. 【ORACLE】ID 2299494.1 安装Oracle 11g 86%报错:Error in invoking target 'agent nmhs' of makefile

    参考: ID 2299494.1 In this Document   Symptoms   Changes   Cause   Solution   References APPLIES TO: O ...

  2. Cassandra概念学习系列之Cassandra是什么?

    不多说,直接上干货! http://cassandra.apache.org/ Apache Cassandra是一套开源分布式NoSQL数据库系统.它最初由Facebook开发,用于储存收件箱等简单 ...

  3. 2-5 js基础-简易运动框架

    'use strict'; function getStyle(obj,sName){ return (obj.currentStyle||getComputedStyle(obj,false))[s ...

  4. 08 Java 集合的线程安全问题

    1 Java中的集合 Java中的集合分为同步的集合(线程安全)和线程不安全的集合 例如 : ArrayList和Vector的区别: 一.同步性:Vector是线程安全的,也就是说是同步的,而Arr ...

  5. CSS3多列Multi-column布局

    Properties 属性 CSS Version 版本 Inherit From Parent 继承性 Description 简介 columns css3 无 设置或检索对象的列数和每列的宽度. ...

  6. 【扫盲】】32位和64位Windows的区别

    用户购买windows安装盘或者重新安装操作系统的时候,通常会遇到这个问题,就是不知道该如何选择使用32位操作系统和64位操作系统,有人说64位系统速度快,其实理论上确实是这样,不过具体还要根据你的个 ...

  7. mklink /d 目录符号链接

    刚装好Windows Live Writer,却发现日志保存路径是默认的改都没法改,在C:\Users\用户名\Documents\My Weblog Posts下. 找了下,竟然可以用cmd的mkl ...

  8. Timer控件

    Timer控件是定期引发事件的控件,时间间隔的长度由interval属性定义,其值以毫秒为单位吗,若启用了该组件,则每个事件间隔引发一个Tick事件,Timer组件的主要方法包括start和stop, ...

  9. .net下 本地锁、redis分布式锁、zk分布式锁的实现

    为什么要用锁? 大型站点在高并发的情况下,为了保持数据最终一致性就需要用到技术方案来支持.比如:分布式锁.分布式事务.有时候我们在为了保证某一个方法每次只能被一个调用者使用的时候,这时候我们也可以锁来 ...

  10. DWF Toolkit on Microsoft Windows

    If you are statically linking on Windows, you need these preprocessor defines: DWFTK_STATIC DWFTK_BU ...