Android HandlerThread详解

概述

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

详细

代码下载:http://www.demodashi.com/demo/10628.html

原文地址:

Android HandlerThread详解 CSDN

Android HandlerThread详解 简书

一、准备工作

开发环境:

jdk1.8

Eclipse Luna Service Release 1 (4.4.1)

运行环境:

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

实现功能:

Android HandlerThread的使用

二、程序实现

1、需要截图程序结构

image.png

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。

1package com.zpengyong.hand; 2 3import android.app.Activity; 4import android.os.Bundle; 5import android.os.Handler; 6import android.os.HandlerThread; 7import android.os.Looper; 8import android.os.Message; 9import android.util.Log; 10import android.view.View; 11import android.view.View.OnClickListener; 12import android.widget.Button; 13import android.widget.TextView; 14 15public class MainActivity extends Activity { 16 private final static String TAG = "MainActivity"; 17 18 private Button mGet; 19 private TextView mResult; 20 21 protected final int MSG_GET = 1; 22 protected final int MSG_RESULT = 2; 23 24 private HandlerThread mHandlerThread; 25 //子线程中的Handler实例。 26 private Handler mSubThreadHandler; 27 //与Ui线程绑定的Handler实例。 28 private Handler mUiHandler = new Handler(){ 29 public void handleMessage(Message msg) { 30 Log.i(TAG, "mUiHandler handleMessage thread:"+Thread.currentThread()); 31 switch (msg.what) { 32 case MSG_RESULT: 33 mResult.setText((String)msg.obj); 34 break; 35 default: 36 break; 37 } 38 }; 39 }; 40 @Override 41 protected void onCreate(Bundle savedInstanceState) { 42 super.onCreate(savedInstanceState); 43 setContentView(R.layout.activity_main); 44 Log.i(TAG, "onCreate thread:"+Thread.currentThread()); 45 mGet = (Button) findViewById(R.id.get); 46 mGet.setOnClickListener(new OnClickListener() { 47 @Override 48 public void onClick(View v) { 49 mSubThreadHandler.sendEmptyMessage(MSG_GET); 50 } 51 }); 52 mResult = (TextView) findViewById(R.id.result); 53 54 initHandlerThraed(); 55 } 56 57 private void initHandlerThraed() { 58 //创建HandlerThread实例 59 mHandlerThread = new HandlerThread("handler_thread"); 60 //开始运行线程 61 mHandlerThread.start(); 62 //获取HandlerThread线程中的Looper实例 63 Looper loop = mHandlerThread.getLooper(); 64 //创建Handler与该线程绑定。 65 mSubThreadHandler = new Handler(loop){ 66 public void handleMessage(Message msg) { 67 Log.i(TAG, "mSubThreadHandler handleMessage thread:"+Thread.currentThread()); 68 switch(msg.what){ 69 case MSG_GET: 70 try { //模拟延时处理 71 Thread.sleep(1000); 72 } catch (InterruptedException e) { 73 e.printStackTrace(); 74 } 75 double number = Math.random(); 76 String result = "number:"+number; 77 //向ui线程发送消息,更新ui。 78 Message message = new Message(); 79 message.what = MSG_RESULT; 80 message.obj = result; 81 mUiHandler.sendMessage(message); 82 break; 83 default: 84 break; 85 } 86 }; 87 }; 88 } 89 90 @Override 91 protected void onDestroy() { 92 super.onDestroy(); 93 Log.i(TAG, "onDestroy"); 94 //退出HandlerThread的Looper循环。 95 mHandlerThread.quit(); 96 } 97}

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

  1. 创建HandlerThread线程

  2. 运行线程

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

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

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

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

点击按钮,向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的构造方法。

1public class HandlerThread extends Thread { 2 int mPriority; 3 int mTid = -1; 4 Looper mLooper; 5 //@param name 线程名 6 public HandlerThread(String name) { 7 super(name); 8 mPriority = Process.THREAD_PRIORITY_DEFAULT; 9 } 10 /** 11 * Constructs a HandlerThread. 12 * @param name 13 * @param priority The priority to run the thread at. The value supplied must be from 14 * {@link android.os.Process} and not from java.lang.Thread. 15 */ 16 public HandlerThread(String name, int priority) { 17 super(name); 18 mPriority = priority; 19 } 20 。。。。

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

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

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

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

1/** 2 * Call back method that can be explicitly overridden if needed to execute some 3 * setup before Looper loops. 4 */ 5protected void onLooperPrepared() { 6} 7@Overridepublic void run() { 8 //获取进程id 9 mTid = Process.myTid(); 10 //创建Looper实例 11 Looper.prepare(); 12 synchronized (this) { 13 //获取当前线程的Looper实例 14 mLooper = Looper.myLooper(); 15 notifyAll(); 16 } 17 //设置线程优先级 18 Process.setThreadPriority(mPriority); 19 onLooperPrepared(); 20 //开始循环 21 Looper.loop(); 22 mTid = -1; 23}

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

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

接着看获取Looper实例

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

对应源码:

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

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

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

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

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

HandlerThread提供的线程退出方法:

1public boolean quit() { 2 Looper looper = getLooper(); 3 if (looper != null) { 4 looper.quit(); 5 return true; 6 } 7 return false; 8} 9public boolean quitSafely() { 10 Looper looper = getLooper(); 11 if (looper != null) { 12 looper.quitSafely(); 13 return true; 14 } 15 return false; 16}

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

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

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

四、其他补充

参考文章:

Android Handler的基本使用

深入理解Handler、Looper、Messagequeue

代码下载:http://www.demodashi.com/demo/10628.html

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

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )