当前位置: 首页 > news >正文

Android面试指南(二)

目录

一、Handler

1.1、什么是Handler

1.2、Handler的使用方法

1.3、Handler的机制原理

1.4、Handler引起的内存泄漏问题

二、AsyncTask

2.1、什么是AsyncTask

2.2、AsyncTask的使用方法(三参五法)

2.3、AsyncTask的机制原理

2.4、AsyncTask注意事项

三、HandlerThread

3.1、HandlerThread产生背景

3.2、HandlerThread是什么

3.3、HandlerThread的特点

3.4、HandlerThread源码解析

四、IntentService

4.1、IntentService是什么

4.2、IntentService使用方法

4.3、IntentService源码解析

一、Handler

推荐阅读:Handler你真的搞懂了吗?

1.1、什么是Handler

android.view.ViewRootImpl$CalledFromWrongThreadException:
Only the original thread that created a view hierarchy can touch its views.
  • 核心定义:Handler是通过发送和处理Message/Runnable对象来关联线程MessageQueue的机制
  • 主要功能:
    • 实现线程间通信(如子线程与主线程)
    • 支持延迟消息处理(未来时间点执行)
    • 解决UI线程安全问题
  • 四大组件:
    • Handler:消息处理器
    • Message:消息载体
    • MessageQueue:消息队列
    • Looper:消息循环器
  • 典型应用场景:
    • 子线程完成文件下载后更新UI
    • 网络请求完成后刷新界面
    • 定时任务执行

1.2、Handler的使用方法

①、通过post(runnable)

  • 实现步骤:
    • 在主线程创建Handler(自动绑定UI线程)
    • 子线程执行耗时操作(如Thread.sleep(5000)模拟下载)
    • 通过handler.post(Runnable)提交UI更新任务
  • 源码本质:最终调用的是sendMessageDelayed()方法

②、通过sendMessage(message)

  • 实现步骤:
    • 创建Handler并重写handleMessage方法
    • 子线程创建Message对象(建议使用Message.obtain())
    • 设置消息标识(what字段)和附加数据(arg1/arg2)
    • 通过handler.sendMessage()发送消息
  • 消息处理:
    • 在handleMessage中通过switch-case处理不同what值
    • 通过msg.what区分消息类型
    • UI操作必须在主线程执行
  • 优势:
    • 更灵活的消息分类处理
    • 可携带复杂数据(通过Bundle)
    • 支持精确的延迟发送
  • 底层原理:
    • postRunnable最终转换为Message发送
    • 所有操作最终进入MessageQueue
    • Looper不断从队列取出消息交给Handler处理
  • 注意事项:
    • 避免内存泄漏(非静态内部类持有外部类引用)
    • 主线程默认创建Looper,子线程需手动准备
    • 消息处理耗时会影响UI流畅度

1.3、Handler的机制原理

①、Handler机制概览:

  • 四大组件:包含Handler、Looper、MessageQueue、Message四个核心部分
  • Looper作用:
    • 每个线程独有,通过ThreadLocal机制保证线程隔离
    • 包含MessageQueue成员变量,创建时即关联消息队列
  • MessageQueue特性:
    • 采用先进先出(FIFO)方式管理Message
    • 通过enqueueMessage()和next()方法实现消息存取
  • Message结构:
    • 包含what、arg1、arg2等基本数据类型字段
    • obj字段可传递复杂对象
    • target字段指向处理该消息的Handler
  • Handler双重功能:
    • 发送消息到关联线程的MessageQueue
    • 处理Looper分发过来的消息

②、Handler的构造方法

  • 关键操作:
    • 通过Looper.myLooper()获取当前线程的Looper
    • 若未调用Looper.prepare()会抛出RuntimeException
  • ThreadLocal机制:
    • 保证不同线程访问同一ThreadLocal时,读写操作仅限于各自线程内部
    • 通过get()方法获取线程独有的Looper实例
  • 主线程特殊性:
    • 必须在UI线程创建Handler才能保证handleMessage()在UI线程执行
    • 避免在非静态内部类创建Handler可能引起的内存泄漏

③、Looper的prepare方法

  • prepare()核心逻辑:
    • 创建新Looper实例并设置到sThreadLocal
    • 每个线程只能调用一次prepare(),否则抛出异常
  • prepareMainLooper():
    • 系统自动为主线程调用,开发者不应手动调用
    • 调用prepare(false)创建不允许退出的Looper
  • loop()工作流程:
    • 创建无限循环,通过queue.next()阻塞获取消息
    • 消息处理后调用msg.target.dispatchMessage()进行分发
    • 无消息时表示消息队列正在退出

④、Handler的dispatchMessage方法

  • 处理优先级:
    • 优先检查Message.callback(Runnable对象)
    • 其次检查Handler.mCallback接口
    • 最后调用Handler.handleMessage()
  • post与sendMessage统一性:
    • 最终都通过sendMessageAtTime()将消息加入队列
    • post(Runnable)会封装为Message.callback
  • 消息循环本质:
    • Looper不断从MessageQueue取消息
    • 通过dispatchMessage()形成"产生-处理-再产生"的闭环

⑤、Handler机制原理总结

  • 完整工作流程:
    • Looper从MessageQueue头部取出Message
    • 通过Message.target找到对应Handler
    • Handler执行handleMessage()处理消息
    • 返回Looper继续下个循环
  • 关键设计思想:
    • 使用ThreadLocal实现线程隔离
    • 通过消息队列实现线程间通信
    • 主线程Looper保证UI操作线程安全

1.4、Handler引起的内存泄漏问题

①、内存泄漏原因

  • 非静态内部类问题: 由于创建的Handler不是静态内部类,会隐式持有外部Activity的引用
  • 回收机制受阻: 当Activity需要回收时,Handler可能正在执行耗时操作导致无法释放
  • 引用链保持: Handler持有的Activity引用无法释放,导致Activity无法被GC回收

②、内存泄漏解决办法

  • 弱引用处理:
    • 在静态内部类中使用WeakReference持有Activity引用
    • 避免直接使用Activity对象创建Handler
  • 静态Handler:
    • 将Handler声明为static静态内部类
    • 切断与外部类的默认引用关系
  • 生命周期管理:
    • 在Activity的onDestroy()中调用handler.removeCallbacks()
    • 及时移除所有待处理消息

二、AsyncTask

2.1、什么是AsyncTask

  • 本质:封装了线程池和Handler的内部框架,是Android提供的轻量级异步任务类
  • 继承方式:需要继承抽象类AsyncTask,在子类中实现异步操作
  • 核心功能:
    • 避免直接使用Thread和Handler处理后台操作
    • 可将运算结果直接交给UI线程显示
  • 适用场景:仅适合执行耗时较短的操作(长时间任务建议使用线程池)

2.2、AsyncTask的使用方法(三参五法)

  • 三个泛型参数:
    • 第一个Integer:执行任务时传入的参数类型
    • 第二个Integer:进度显示单位类型
    • 第三个String:任务执行结果的返回类型
  • 五个核心方法:
    • onPreExecute:在UI线程调用,用于任务前初始化(如显示进度条)
    • doInBackground:在工作线程执行耗时操作,必须返回计算结果
    • onProgressUpdate:通过publishProgress触发,动态更新进度
    • onPostExecute:接收doInBackground返回结果并在UI线程显示
    • publishProgress:在doInBackground中调用,触发进度更新

2.3、AsyncTask的机制原理

  • AsyncTask本质:静态线程池,所有子类任务都提交到该线程池执行
  • 执行流程:
    • 工作线程执行doInBackground方法
    • 任务状态改变后通过InternalHandler向UI线程发送消息
    • Handler机制响应消息并调用对应回调方法
  • 底层实现:基于线程池和Handler的消息传递机制

2.4、AsyncTask注意事项

  • 内存泄漏:
    • 原因:非静态内部类持有Activity引用
    • 解决方案:使用静态内部类+弱引用,在onDestroy中cancel任务
  • 生命周期:
    • 必须主动调用cancel(),否则任务会继续执行
    • 需在onDestroy中取消任务避免崩溃
  • 结果丢失:
    • 场景:屏幕旋转/Activity被系统回收后重建
    • 原因:持有无效Activity引用导致onPostExecute失效
  • 并行与串行:
    • 历史变更:1.6前串行→1.6-2.3并行→2.3后默认串行
    • 建议:使用默认串行保证稳定性,必要时调用executeOnExecutor并行

三、HandlerThread

3.1、HandlerThread产生背景

  • 耗时操作问题:在Android中执行耗时操作时通常需要开启子线程,但线程执行完后会被销毁,频繁创建销毁线程会消耗系统资源。
  • 循环线程解决方案:通过构建带有Looper的循环线程,使线程执行完任务后处于阻塞等待状态,避免重复创建销毁。
  • 封装优化:HandlerThread是为解决上述问题而封装的框架,内部已实现Looper轮询机制。

3.2、HandlerThread是什么

  • 本质组成:HandlerThread = Handler + Thread + Looper,是一个内部包含Looper的Thread子类。
  • 与普通线程区别:普通子线程默认没有Looper,而HandlerThread内部自动创建了Looper对象。

3.3、HandlerThread的特点

  • 继承关系:继承自Thread类,但内部创建了Looper对象支持消息循环。
  • 异步任务处理:通过获取HandlerThread的Looper创建Handler,可在handleMessage()中执行异步任务。
  • 非UI线程优势:内部Looper不会干扰UI线程,避免阻塞主线程。
  • 串行执行特点:任务按顺序执行,不能同时处理多任务,但保证了线程安全。
  • 与线程池对比:不同于线程池的并发机制,HandlerThread是单线程串行队列,更安全但效率较低。

3.4、HandlerThread源码解析

public class HandlerThread extends Thread {Looper mLooper;@Overridepublic void run() {mTid = Process.myTid();Looper.prepare();synchronized (this) {mLooper = Looper.myLooper();notifyAll();}Process.setThreadPriority(mPriority);onLooperPrepared();Looper.loop();mTid = -1;}
}
  • 成员变量:
    • mLooper:持有的Looper对象
    • mPriority:线程优先级
    • mTid:线程ID
  • 构造方法:
    • 可指定线程名称和优先级(优先级需使用android.os.Process的常量)
  • 关键方法:
    • onLooperPrepared():空方法,供重写用于Looper循环前的初始化
    • run()核心逻辑:初始化Looper并启动循环,同步代码块通过 wait/notifyAll 保证线程安全
  • 线程同步机制:
    • 使用synchronized代码块保证线程安全
    • 通过wait/notifyAll实现线程间通信
    • getLooper()会阻塞等待直到run()方法完成Looper初始化
  • 退出方法:
    • quit():立即退出Looper
    • quitSafely():安全退出(处理完当前消息后退出),效率较低但更安全

四、IntentService

4.1、IntentService是什么

  • 基本定义:IntentService是继承并处理异步请求的类,继承自Service且优先级更高
  • 核心特性:
    • 内部封装HandlerThread和Handler实现异步处理
    • 自动停止机制:任务完成后自动停止,无需手动调用stopSelf()
    • 串行执行:多个任务按队列顺序执行,每次只处理一个线程

4.2、IntentService使用方法

  • 实现方式:
    • 必须实现构造方法:需传入线程名称字符串
    • 必须重写onHandleIntent:执行核心耗时操作
  • 调用方式:
    • 通过startService()启动
    • Intent可携带参数传递给onHandleIntent
  • 注意事项:
    • 即使循环启动多次,实际只有一个实例
    • 消息队列保证任务不被覆盖

4.3、IntentService源码解析

①、onCreate方法

  • 初始化流程:
    • 创建HandlerThread工作线程
    • 获取线程的Looper对象
    • 创建ServiceHandler绑定Looper
  • 关键设计:
    • HandlerThread保证异步执行环境
    • Looper实现消息队列机制

②、onStartCommand方法

  • 任务调度:
    • 通过ServiceHandler发送消息
    • 消息包含Intent和任务ID
  • 重传机制:
    • 支持设置intentRedelivery
    • 进程异常终止时可恢复最近任务

③、ServiceHandler类

  • 处理流程:
    • 调用onHandleIntent执行实际任务
    • 任务完成后调用stopSelf(msg.arg1)
  • 停止机制:
    • 带参数的stopSelf会等待所有消息处理完毕
    • 确保最后一个任务完成才销毁服务
  • 核心设计:
    • 消息队列保证任务顺序执行
    • 每个消息独立处理不互相干扰

OK,今天的内容就这么多了,下期再会!

http://www.lryc.cn/news/624054.html

相关文章:

  • 如何让AI视频模型(如Veo)开口说中文?一个顶级提示词的深度拆解
  • 深入解析Tomcat Processor的协议处理机制
  • Linux Shell定时检查日期执行Python脚本
  • 安装pytorch3d后报和本机cuda不符
  • 照相机标定-动手学计算机视觉16
  • 计算机网络 Cookie 和 Session 的区别详解
  • 【递归、搜索与回溯算法】记忆化搜索
  • C语言零基础第19讲:自定义类型—联合体和枚举
  • 1. Docker的介绍和安装
  • 区块链练手项目(持续更新)
  • 电容,三极管,场效应管
  • 【状压DP】3276. 选择矩阵中单元格的最大得分|2403
  • 电动车安全技术全解析:从传统制动到智能驾驶的技术革命
  • MySQL深度理解-MySQL8新特性
  • 三种变量类型在局部与全局作用域的区别
  • 深入理解C#特性:从应用到自定义
  • 一起Oracle 19c bug 导致的业务系统超时问题分析
  • 嵌入式C语言学习笔记之枚举、联合体
  • Jenkins - CICD 注入环境变量避免明文密码暴露
  • 图解直接插入排序C语言实现
  • 跨越南北的养老对话:为培养“银发中国”人才注入新动能
  • 数据准备|生成折线图
  • Python自学09-常用数据结构之元组
  • Java语法进阶之常用类
  • 【新手入门】Android基础知识(二):Binder进程间通信,理解Binder工作原理以及Binder实体、Binder引用、Binder代理概念
  • K8S集群环境搭建(一)
  • 双指针和codetop2(最短路问题BFS)
  • Maven依赖范围
  • 检查xrdp远程连接桌面卡顿的问题(附解决sh脚本)
  • STM32入门之USART串口部分