Android HandlerThread 总结使用

2023-10-27

前言

以前我在 【Android Handler、Loop 的简单使用】 介绍了子线程和子线程之间的通信。
这里写图片描述

很明显的一点就是,我们要在子线程中调用Looper.prepare() 为一个线程开启一个消息循环,默认情况下Android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。) Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。 然后通过Looper.loop() 让Looper开始工作,从消息队列里取消息,处理消息。

注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。

然而这一切都可以用HandlerThread类来帮我们做这些逻辑操作。

HandlerThread

HandlerThread本质上就是一个普通Thread,只不过内部建立了Looper.

HandlerThread的常规用法

  • 创建一个HandlerThread

mThread = new HandlerThread("handler_thread");

  • 启动一个HandlerThread

    mThread.start();

  • 退出循环
    Looper是通过调用loop方法驱动着消息循环的进行: 从MessageQueue中阻塞式地取出一个消息,然后让Handler处理该消息,周而复始,loop方法是个死循环方法。

那如何终止消息循环呢?我们可以调用Looper的quit方法或quitSafely方法,二者稍有不同。

 /**
     * Quits the looper.
     * <p>
     * Causes the {@link #loop} method to terminate without processing any
     * more messages in the message queue.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p><p class="note">
     * Using this method may be unsafe because some messages may not be delivered
     * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
     * that all pending work is completed in an orderly manner.
     * </p>
     *
     * @see #quitSafely
     */
    public void quit() {
        mQueue.quit(false);
    }

    /**
     * Quits the looper safely.
     * <p>
     * Causes the {@link #loop} method to terminate as soon as all remaining messages
     * in the message queue that are already due to be delivered have been handled.
     * However pending delayed messages with due times in the future will not be
     * delivered before the loop terminates.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p>
     */
    public void quitSafely() {
        mQueue.quit(true);
    }

相同点:
将不在接受新的事件加入消息队列。

不同点
当我们调用Looper的quit方法时,实际上执行了MessageQueue中的removeAllMessagesLocked方法,该方法的作用是把MessageQueue消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过sendMessageDelayed或通过postDelayed等方法发送的需要延迟执行的消息)还是非延迟消息。

当我们调用Looper的quitSafely方法时,实际上执行了MessageQueue中的removeAllFutureMessagesLocked方法,通过名字就可以看出,该方法只会清空MessageQueue消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让Handler去处理,quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息。

无论是调用了quit方法还是quitSafely方法只会,Looper就不再接收新的消息。即在调用了Looper的quit或quitSafely方法之后,消息循环就终结了,这时候再通过Handler调用sendMessage或post等方法发送消息时均返回false,表示消息没有成功放入消息队列MessageQueue中,因为消息队列已经退出了。

需要注意的是Looper的quit方法从API Level 1就存在了,但是Looper的quitSafely方法从API Level 18才添加进来。

小例子:

package com.app;

import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private HandlerThread myHandlerThread ;
    private Handler handler ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //创建一个线程,线程名字:handler-thread
        myHandlerThread = new HandlerThread( "handler-thread") ;
        //开启一个线程
        myHandlerThread.start();
        //在这个线程中创建一个handler对象
        handler = new Handler( myHandlerThread.getLooper() ){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //这个方法是运行在 handler-thread 线程中的 ,可以执行耗时操作
                Log.d( "handler " , "消息: " + msg.what + "  线程: " + Thread.currentThread().getName()  ) ;

            }
        };

        //在主线程给handler发送消息
        handler.sendEmptyMessage( 1 ) ;

        new Thread(new Runnable() {
            @Override
            public void run() {
             //在子线程给handler发送数据
             handler.sendEmptyMessage( 2 ) ;
            }
        }).start() ;

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        //释放资源
        myHandlerThread.quit() ;
    }
}

运行效果:

/com.app D/handler: 消息: 1  线程: handler-thread
/com.app D/handler: 消息: 2  线程: handler-thread

HandlerThread的特点

  • HandlerThread将loop转到子线程中处理,说白了就是将分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅。

  • 开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。HandlerThread本质是一个线程,在线程内部,代码是串行处理的。

  • 但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。

  • HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。

  • 对于网络IO操作,HandlerThread并不适合,因为它只有一个线程,还得排队一个一个等着。

参考文章:

Android Handler、Loop 的简单使用
Android 如何有效的解决内存泄漏的问题
Android 更新UI的几种方式


from:http://www.cnblogs.com/zhaoyanjun/p/6062880.html





本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android HandlerThread 总结使用 的相关文章

  • 基于stm32作品设计:多功能氛围灯、手机APP无线控制ws2812,MCU无线升级程序

    文章目录 一 作品背景 二 功能设计与实现过程 三 实现基础功能 一 首先是要选材 二 原理图设计 二 第一版本PCB设计 三 焊接PCB板 四 编写单片机程序 五 下载程序验证 四 外壳设计 一 CAD图纸设计 二 磨砂亚克力板 五 重新
  • [Git] 代码管理之 Git(六)Git rebase 压缩提交历史

    我们在工作中 可能会出现这样的情况 一项工作由好几个同事同时完成 然后每个人针对当前的feature都有对应的提交 那么就会造成同一个feature有多次提交的这样的冗余存在 除此之外 如果我们自己针对同一个feature的每天的提交以及一
  • JVM(六)方法调用(补充知识)

    方法调用并不等同于方法中的代码被执行 方法调用阶段唯一的任务就是确定被调用方法的版本 即调用哪一个方法 暂时还未涉及方法内部的具体运行过程 一切方法调用在Class文件里面存储的都只是符号引用 而不是方法在实际运行时内存布局中的入口地址 也
  • 关于H264相关的EBSP,RBSP,SODP的说明

    1 关于H264相关的EBSP RBSP SODP的说明 1 EBSP 扩展字节序列载荷 Encapsulated Byte Sequence Payload 它去掉了00 00 01 00 00 00 01这些起始码 但包含了0x3防止竞
  • 时序约束优先级_静态时序分析圣经翻译计划——附录A:SDC

    本附录将介绍1 7版本的SDC格式 此格式主要用于指定设计的时序约束 它不包含任何特定工具的命令 例如链接 link 和编译 compile 它是一个文本文件 可以手写或由程序创建 并由程序读取 某些SDC命令仅适用于实现 implemen
  • @Around简单使用示例——SpringAOP增强处理

    Around的作用 既可以在目标方法之前织入增强动作 也可以在执行目标方法之后织入增强动作 可以决定目标方法在什么时候执行 如何执行 甚至可以完全阻止目标目标方法的执行 可以改变执行目标方法的参数值 也可以改变执行目标方法之后的返回值 当需
  • 如何搭建Spring开发环境呢?

    转自 如何搭建Spring开发环境呢 下文讲述搭建Spring开发环境的方法分享 如下所示 由于Spring是基于Java代码的一个框架 所以在Spring环境搭建之前 我们需为开发环境安装好 JDK Java开发环境 Eclipse Ja
  • 来自ebay内部的「软件测试」学习资料,覆盖GUI、API自动化、代码级测试及性能测试等,Python等,拿走不谢!...

    在软件测试领域从业蛮久了 常有人会问我 刚入测试一年 很迷茫 觉得没啥好做的 测试在公司真的不受重视 我是不是去转型做开发会更好 资深的测试架构师的发展路径是怎么样的 我平时该怎么学习 我估计不少人有这样的想法 甚至你也会被身边的人所影响
  • React 中constructor 作用

    React 中constructor 作用 react中的constructor大体有两个作用 1 初始化this state 2 纠正方法的this的指向 constructor props super props this state
  • 大数据毕设 python+深度学习+opencv实现植物识别算法系统

    文章目录 0 前言 2 相关技术 2 1 VGG Net模型 2 2 VGG Net在植物识别的优势 1 卷积核 池化核大小固定 2 特征提取更全面 3 网络训练误差收敛速度较快 3 VGG Net的搭建 3 1 Tornado简介 1 优
  • LWIP学习笔记(2)---IP协议实现细节

    IP头 收到的数据首先保存在pbuf结构中 The IPv4 header struct ip hdr version header length PACK STRUCT FLD 8 u8 t v hl type of service PA
  • C++11线程库 (六) 条件变量 Condition variables

    一 什么是条件变量 条件变量类 condition variable 是一个同步原语 它可以在同一时间阻塞一个线程或者多个线程 直到其他线程改变了共享变量 条件 并通知 primitive 原语 表达的是基础 基本的 是其他复杂应用的构建基
  • 基于高德地图的描点操作,监听地图缩放,展示合理数量的marker

    1 根据两点经纬度算两点之间的距离函数 function Rad d return d Math PI 180 0 经纬度转换成三角函数中度分表形式 计算距离 参数分别为第一点的纬度 经度 第二点的纬度 经度 function GetDis
  • java缓存面试问题_分布式缓存的面试题5

    1 面试题 如何保证Redis的高并发和高可用 redis的主从复制原理能介绍一下么 redis的哨兵原理能介绍一下么 2 面试官心里分析 其实问这个问题 主要是考考你 redis单机能承载多高并发 如果单机扛不住如何扩容抗更多的并发 re
  • R语言数据输入

    一 使用键盘输入数据 在导入数据比较少的时候 我们使用这种方法 R中的函数 edit 会自动调用一个允许手动输入数据的文本编辑器 具体步骤如下 1 创建一个空数据框 或矩阵 其中变量名和变量的模式需与理想中的最终数据集一致 2 针对这个数据

随机推荐

  • java使用aspose将word,excel,ppt转pdf

    1 测试环境springboot jdk1 8 aspose cells 8 5 2 jar 用于转换xls aspose words 16 8 0 jdk16 jar 用于转换doc 2 所用jar 签名百度网盘地址 链接 https p
  • Pytorch加载自己的数据集(以图片格式的Mnist数据集为例)

    文章目录 Pytorch加载自己的数据集 以图片格式的Mnist数据集为例 前言 一 数据集转换 二 构建自己的数据集 1 引入库 2 构建MnistDataset类 3 搭建网络模型 三 完整代码 总结 Pytorch加载自己的数据集 以
  • 【最新更新】2020研究生华为杯数学建模比赛题目+题目分析【持续更新】

    各参赛队伍 为了保证2020年 华为杯 第十七届中国研究生数学建模竞赛顺利举行 现将竞赛开赛的相关事项通知如下 一 时间节点 1 加密题目开始下载时间 2020年9月16日8 00 截止时间 2020年9月20日17 00 2 题目解密密码
  • 强化学习 OpenAI Gym Universe Docker在Windows WSL 2安装配置最全的全记录

    1 事情的起源 全记录事情的起源是为了学习Python强化学习实战 先在自己的windows操作系统的Pycharm Anaconda Gym配置下运行成功了CartPole示例和CarRacing示例 接着运行Universe 据说Ope
  • JVM 与 GC 讲解

    文章目录 一 概述 二 JVM 内存模型 三 GC算法和回收器 1 垃圾回收算法 2 垃圾回收器 四 垃圾回收机制 GC 1 分代垃圾回收机制 2 G1 垃圾回收器 3 FullGC 机制 一 概述 JVM Java Virtual Mac
  • Retrofit2+Rxjava2+Rxandroid+okhttp3+Lifecycle 的MVP网络框架,精简Google官方AAC框架,实现APP生命周期的管理

    一 介绍 目前使用较为广泛的网络请求框架 MVP Retrofit2 okhttp3 Rxjava2 我于2017年也加入了使用行列 在网上找了许多案例 实际项目开发中解决了一些所谓的坑 总结了些内容与大家共享一下 1 什么是MVP 在图中
  • 优惠价,百分比计算,折扣计算,打折计算

    一 优惠价 百分比计算 例如 原价是100元 优惠5 5 5 100 0 05 优惠价 100x5 100x0 05 5 计算得出优惠价是5元 优惠后的价格 原价 优惠价 95 100 5 计算得出优惠后的价格是95元 例如 原价是100元
  • 理解DDoS防护本质:基于资源较量和规则过滤的智能化系统

    本文由 网易云 发布 随着互联网生态逐渐形成 DDoS防护已经成为互联网企业的刚需要求 网易云安全 易盾 工程师根据DDoS的方方面面 全面总结DDoS的攻防对抗 1 什么是DDoS DDoS全称Distributed Denial of
  • steam deck科普、上手教程及模拟器配置指南

    steam deck 前言 早在2021年得时候 坊间就开始流传steam deck这个东西要问世了 但是中途跳了几次票 直到2022年2月 第一批steam deck才正式面向大众玩家 在熟悉steam deck之前 我们有必要了解如下的
  • VS2019 + libcurl5.7.0 + openssl3.0.5 简易编译教程

    VS2019 libcurl5 7 0 openssl编译配置 1 用途 工作用到C 对求高德地图发送https请求 进行逆地址分析 2 文件包下载 2 1 window的openssl3 0 5EXE安装包 链接 exe安装包 2 2 下
  • numpy求平均值

    本文转自链接 https www cnblogs com yibeimingyue p 11413295 html 1 对数组求平均值 import numpy as np a np array 1 2 3 4 print a print
  • C语言问题汇总

    C语言问题汇总 排序方法 冒泡排序 降序排序 作业 从文件中读取内容 字符写入文件 结构体数组 以二进制形式写入文件并读取 将字符串写入文件 并从文件中读取 查找字符在字符串中的位置 字符串链接 不使用strcpy函数 使用strcpy函数
  • 俄罗斯方块C++代码(转载他人代码)

    include
  • (ctf)攻防世界web模块020web2

    题目 首先来到给定的地址 题意很明确 miwen是加密之后的字符串 我们只需要逆向解密出miwen就能得到flag 我们先来代码审计 o strrev str strrev 函数是字符串的倒置 for 0 0 0
  • java.io.IOException: Connection reset by peer问题解决

    java io IOException Connection reset by peer问题解决 今天检查日志 发现 ClientAbortException java io IOException Connection reset by
  • font-spider(字蛛)的正确打开方式

    前言 最近在部署vue项目之后 在打开网页的时候 ttf文件下载时间实在是太久了 在经过合理的运用搜索引擎之后 可能自己的固化思维消化不了大佬们给出的方案 于是在他们的基础之上做了一些小小的改动 便叙文记之 1 引入font spider的
  • BigDecimal 前端丢失精度的问题解决

    问题描述 后端数字是85 00 但是前端显示85 SQL语句 select cast 字段 as decimal 10 2 value 这里已经保留两位小数了 from table where 实体类 这里是关键 注意不是 JSONFiel
  • java 的JDBC操作

    JDBC java数据库连接 提供了一套数据库操作标准 这些标准需要各个数据库厂商去实现并提供一个驱动程序 目前常见的4类JDBC驱动程序 JDBC ODBC 直接利用微软的ODBC进行数据库连接操作 性能低 一般不推荐 JDBC本地驱动
  • 前端笔记

    发布在github的笔记 下载慢 所以我放到csdn上面了 源地址 https github com overcomputer JavaScript 源地址 关注 大佬发布在github的笔记 下载慢 所以我放到csdn上面了 源地址 ht
  • Android HandlerThread 总结使用

    前言 以前我在 Android Handler Loop 的简单使用 介绍了子线程和子线程之间的通信 很明显的一点就是 我们要在子线程中调用Looper prepare 为一个线程开启一个消息循环 默认情况下Android中新诞生的线程是没