概述

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. arcgis python添加几何属性

    import arcpy import numpy import math def AddGeometryAttributes(fc, geomProperties, lUnit, aUnit, cs ...

  2. arcgis runtime 100 Create geometries

    1 /* Copyright 2016 EsriEsri 2 * 3 * Licensed under the Apache License, Version 2.0 (the "Licen ...

  3. 解决eclipse安装maven的问题:Unable to update index for central|http://repo1.maven.org/maven2

    问题产生如下:因为单位使用了过滤,访问Internet时,超过10M的内容就拒绝.因为maven插件在初始时,需要下载Maven的index文件,这个文件比较大,有38M多,下载不成功.所以造成使用M ...

  4. jsp中生成txt文件

    import jxl.Workbook; import jxl.write.Label; import jxl.write.WritableSheet; import jxl.write.Writab ...

  5. from __future__ import print_function

    1.在python2.x的环境是使用下面语句,则第二句语法检查通过,第三句语法检查失败 from __future__ import print_function priint('good') pri ...

  6. C++代码文件名标准化处理工具

    工具功能:批量处理C++代码文件,将C++代码文件名中大写字母改为下划线+小写字母. 为了方便代码在不同平台下的移植,代码文件命名规范为:不使用大写字母,单词之间用下划线间隔开.为此写了这个小工具,将 ...

  7. unity forward renderer的 base pass rt设置

    一般他都是用 RenderTexture::SetActive()来设置rt 但是 forward path 的opaque我跟了好久找不到这个setactive 在dorender之前有setupR ...

  8. 动态图片 Movie android-gif-drawable GifView

    Movie 类 文档位置:/sdk/docs/reference/android/graphics/Movie.html 官方对这个类连一句介绍都没有,并且所有的方法也没有一行注释,可见多么不受重视! ...

  9. 25个精致的IPHONE 6和APPLE WATCH原型下载!

    自iPhone 6 和Apple Watch那场的发布会后,很多设计师开始创作相关的原型素材,值得感谢的是,这些作品有好多都无私分享到了网上,不仅可个人使用,也可商用.今天我们收集了从这组免费的素材中 ...

  10. 解决ArcEngine开发程序“假死”现象

    在GIS数据处理中,数据量大是一个非常伤脑筋的问题.最近,在写一个CAD注记转Shapefile文件时,又遇到这个问题. 曾经处理一次数据,达130万个点,即测试区域内的栅格转成点全部处理,程序是写好 ...