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,今天的内容就这么多了,下期再会!