概述

Android HandlerThread使用,自带Looper消息循环的快捷类。

详细

原文地址:

Android HandlerThread详解 CSDN

Android HandlerThread详解 简书

一、准备工作

开发环境:

jdk1.8

Eclipse Luna Service Release 1 (4.4.1)

运行环境:

华为荣耀6(Android4.4)、华为p9(Android7.0)

实现功能:

Android HandlerThread的使用

二、程序实现

1、需要截图程序结构

HandlerThread类介绍

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.

HandlerThread是Android API提供的一个方便、便捷的类,使用它我们可以快速的创建一个带有Looper的线程。Looper可以用来创建Handler实例。注意:start()仍然必须被调用。

如下是HandlerThread使用的demo。

package com.zpengyong.hand;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView; public class MainActivity extends Activity {
private final static String TAG = "MainActivity"; private Button mGet;
private TextView mResult; protected final int MSG_GET = 1;
protected final int MSG_RESULT = 2; private HandlerThread mHandlerThread;
//子线程中的Handler实例。
private Handler mSubThreadHandler;
//与Ui线程绑定的Handler实例。
private Handler mUiHandler = new Handler(){
public void handleMessage(Message msg) {
Log.i(TAG, "mUiHandler handleMessage thread:"+Thread.currentThread());
switch (msg.what) {
case MSG_RESULT:
mResult.setText((String)msg.obj);
break;
default:
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "onCreate thread:"+Thread.currentThread());
mGet = (Button) findViewById(R.id.get);
mGet.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mSubThreadHandler.sendEmptyMessage(MSG_GET);
}
});
mResult = (TextView) findViewById(R.id.result); initHandlerThraed();
} private void initHandlerThraed() {
//创建HandlerThread实例
mHandlerThread = new HandlerThread("handler_thread");
//开始运行线程
mHandlerThread.start();
//获取HandlerThread线程中的Looper实例
Looper loop = mHandlerThread.getLooper();
//创建Handler与该线程绑定。
mSubThreadHandler = new Handler(loop){
public void handleMessage(Message msg) {
Log.i(TAG, "mSubThreadHandler handleMessage thread:"+Thread.currentThread());
switch(msg.what){
case MSG_GET:
try { //模拟延时处理
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
double number = Math.random();
String result = "number:"+number;
//向ui线程发送消息,更新ui。
Message message = new Message();
message.what = MSG_RESULT;
message.obj = result;
mUiHandler.sendMessage(message);
break;
default:
break;
}
};
};
} @Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy");
//退出HandlerThread的Looper循环。
mHandlerThread.quit();
}
}

上述代码比较简单,功能也比较简单,可以在此基础上进行扩展。 
在Actvitiy创建的时候调用initHandlerThraed()函数:

  1. 创建HandlerThread线程

  2. 运行线程

  3. 获取HandlerThread线程中的Looper实例

  4. 通过Looper实例创建Handler实例,从而使mSubThreadHandler与该线程连接到一起。

多次点击按钮,打印信息如下所示:

07-13 05:15:07.662: I/MainActivity(1472): onCreate thread:Thread[main,5,main]
07-13 05:15:45.382: I/MainActivity(1472): mSubThreadHandler handleMessage thread:Thread[handler_thread,5,main]
07-13 05:15:46.402: I/MainActivity(1472): mUiHandler handleMessage thread:Thread[main,5,main]
07-13 05:15:46.412: I/MainActivity(1472): mSubThreadHandler handleMessage thread:Thread[handler_thread,5,main]
07-13 05:15:47.412: I/MainActivity(1472): mUiHandler handleMessage thread:Thread[main,5,main]
.....

点击按钮,向mSubThreadHandler发送消息,mSubThreadHandler中接收到消息进行处理,由打印可知mSubThreadHandler的handleMessage方法运行在子线程中。 
模拟耗时操作,生成随机数,然后向主线程中(mUiHandler)发送消息(Message)。

mUiHandler的handleMessage方法运行在主线程,可以用来更新Ui界面。

Activity销毁的时候,调用mHandlerThread.quit(),退出HandlerThread的Looper循环。

效果图如下: 

【运行方式:右键项目:Run as -》Android Application (备注:Eclipse需要配置Android开发环境)】

三、源码解析

源码路径路径:frameworks/base/core/Java/android/os/HandlerThread.java

先看下HandlerThread的构造方法。

public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
//@param name 线程名
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;
}
。。。。

HandlerThread是Thread(线程)的子类。创建一个HandlerThread实例,也就是创建了一个特殊的线程实例。 
HandlerThread提供了两个构造方法:

  • HandlerThread(String name) 参数为线程名称,线程优先级为Process.THREAD_PRIORITY_DEFAULT。

  • HandlerThread(String name, int priority),name为线程名称,priority为设置的线程优先级。

我们知道线程需要通过start()方法来运行线程,HandlerThread也是这样的。接着看下线程运行的run()方法。

/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
@Overridepublic void run() {
//获取进程id
mTid = Process.myTid();
//创建Looper实例
Looper.prepare();
synchronized (this) {
//获取当前线程的Looper实例
mLooper = Looper.myLooper();
notifyAll();
}
//设置线程优先级
Process.setThreadPriority(mPriority);
onLooperPrepared();
//开始循环
Looper.loop();
mTid = -1;
}

由run方法可知HandlerThrea线程运行创建了Looper实例,并开启了Looper循环,循环从消息队列中获取消息并给Handler进行处理。对于Looper不太明白的可以参考这篇深入理解Handler、Looper、Messagequeue

onLooperPrepared()在Looper循环之前调用,如果需要在Looper循环之前执行一些设置,可以显式覆盖此方法。

接着看获取Looper实例

//获取HandlerThread线程中的Looper实例
Looper loop = mHandlerThread.getLooper();

对应源码:

//此方法返回与此线程关联的Looper。 如果此线程未启动或由于任何原因isAlive()返回false,此方法将返回null。
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// 如果这个线程已经启动,将会被阻塞,直到mLooper被初始化为止。
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}

mHandlerThread.getLooper()获取与该线程绑定的Looper实例。mLooper是在HandlerThread的run()方法中赋值的(也就是在子线程中),getLooper是我们在主线程中调用,该方法会阻塞直到mLooper赋值。

然后demo中通过该looper实例创建Handler.

//创建Handler与该线程绑定。
mSubThreadHandler = new Handler(loop)

你可能会好奇为什么要这样长久Handler而不是“new Handler()“这样呢?因为我们要创建的Handler要与子线程绑定到一起,要处理子线程中的消息,所以要通过子线程中的looper(有线程对应的消息队列)实例创建Handler。这样通过mSubThreadHandler发送的消息会添加到子线程中的消息队列中,然后Looper实例消息进行分发,交给mSubThreadHandler进行处理。

HandlerThread提供的线程退出方法:

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;
}

quit和quitSafely都是退出HandlerThread的消息循环。其分别调用Looper的quit和quitSafely方法。 
quit方法会将消息队列中的所有消息移除(延迟消息和非延迟消息)。 
quitSafely会将消息队列所有的延迟消息移除,非延迟消息派发出去让Handler去处理。quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息

HandlerThread适合处理本地IO读写操作(数据库,文件),因为本地IO操作大多数的耗时属于毫秒级别,对于单线程 + 异步队列的形式 不会产生较大的阻塞。而网络操作相对比较耗时,容易阻塞后面的请求,因此在这个HandlerThread中不适合加入网络操作。

至此HandlerThread就说完了。有什么问题欢迎大家指正、交流。

四、其他补充

参考文章:

Android Handler的基本使用

深入理解Handler、Looper、Messagequeue

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

Android HandlerThread详解的更多相关文章

  1. Android HandlerThread 详解

    概述 HandlerThread 相信大家都比较熟悉了,从名字上看是一个带有 Handler 消息循环机制的一个线程,比一般的线程多了消息循环的机制,可以说是Handler + Thread 的结合, ...

  2. android handle详解3 ThreadHandler

    在android handle详解2的基础上,我们来学习ThreadHandler ThreadHandler的本质就是对android handle详解2的实现 HandlerThread其实还是一 ...

  3. Android Notification 详解(一)——基本操作

    Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...

  4. Android Notification 详解——基本操作

    Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...

  5. Android ActionBar详解

    Android ActionBar详解 分类: Android2014-04-30 15:23 1094人阅读 评论(0) 收藏 举报 androidActionBar   目录(?)[+]   第4 ...

  6. Android 签名详解

    Android 签名详解 AndroidOPhoneAnt设计模式Eclipse  在Android 系统中,所有安装 到 系统的应用程序都必有一个数字证书,此数字证书用于标识应用程序的作者和在应用程 ...

  7. Android编译系统详解(一)

    ++++++++++++++++++++++++++++++++++++++++++ 本文系本站原创,欢迎转载! 转载请注明出处: http://blog.csdn.net/mr_raptor/art ...

  8. Android布局详解之一:FrameLayout

      原创文章,如有转载,请注明出处:http://blog.csdn.net/yihui823/article/details/6702273 FrameLayout是最简单的布局了.所有放在布局里的 ...

  9. 【整理修订】Android.mk详解

    Android.mk详解 1. Android.mk 的应用范围 Android.mk文件是GNU Makefile的一小部分,它用来对Android程序进行编译. 一个Android.mk文件可以编 ...

随机推荐

  1. 兼容的动态加载JS【原】

    兼容的动态加载JS 屌丝就是悲剧,五一还得宅家里写程序专研技术. 说起动态加载JS,搞web的肯定不陌生,著名的YUI库就有强大的模块化的动态加载JS机制.在代码量不断庞大的今天,动态加载JS作用还是 ...

  2. EasyUI 常规用法

    (function () {     // 获取树的路径,如 组织分类 > YHBH > 湖南省卫生厅 > 湖南省长沙市     var getBreadcrumbs = funct ...

  3. 【BZOJ】【1419】Red is good

    数学期望/期望DP 还是戳<浅析竞赛中一类数学期望问题的解决方法>这篇论文…… $$ f[i][j]= \begin{cases} 0 &, &i==0 \\ f[i-1] ...

  4. 【BZOJ】【3170】【TJOI2103】松鼠聚会

    切比雪夫距离+曼哈顿距离 题解:http://www.cnblogs.com/zyfzyf/p/4105456.html 其实应该先做这题再做[BZOJ][3210]花神的浇花集会的吧…… 我们发现d ...

  5. 同步FIFO的设计

    module scfifo #( , ) ( input clk, input rst_n, input wren, input rden, :] din, :] dout, output full, ...

  6. OpenCV学习(34) 点到轮廓的距离

    在OpenCV中,可以很方便的计算一个像素点到轮廓的距离,计算距离的函数为: double pointPolygonTest(InputArray contour, Point2f pt, bool ...

  7. Mysql数据库事务及隔离级别学习测试

    参考了这篇文章的一些内容: http://xm-king.iteye.com/blog/770721 记住以下这张表: 我在springdemo库里面建了一个表: CREATE TABLE `tx` ...

  8. 监听视图树 ViewTreeObserver 获取View的宽高

    前奏:在哪里可以获取到View的宽高 我们知道,在onCreate方法执行完毕以后,View才开始被测量,所以我们在onCreate方法里面通过view.getWidth()或view.getMeas ...

  9. YUI+Ant 实现JS CSS压缩

    今天研究了一下YUI yahoo开源框架,感觉很猛啊. 于是乎我做了一个YUI的ant实现,网上好多关于bat的实现,我就另辟蹊径,出个关于这个的ant实现,嘿嘿独一无二的文章,如果转载的话,其注明作 ...

  10. 科幻大片中那些牛X代码真相

    在<黑客帝国>中,救世主Neo的队友通过屏幕上"1"和"0"构成的数据流,就能看到鲜活的画面,这应该算是科幻大片中对代码最极致的表现了.其他科幻电影 ...