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

Android学习总结之扩展基础篇(一)

一、IdleHandler工作原理

1. IdleHandler 接口定义

IdleHandler 是 MessageQueue 类中的一个接口,定义如下:

public static interface IdleHandler {/*** 当消息队列空闲时会调用此方法。* @return 如果返回 true,则该 IdleHandler 会保留在消息队列中,下次空闲时会再次调用;*         如果返回 false,则该 IdleHandler 会从消息队列中移除。*/boolean queueIdle();
}

2. IdleHandler 的添加

要使用 IdleHandler,需要通过 MessageQueue 的 addIdleHandler() 方法将其添加到消息队列中。以下是 addIdleHandler() 方法的源码:

// MessageQueue.java
public void addIdleHandler(@NonNull IdleHandler handler) {if (handler == null) {throw new NullPointerException("Can't add a null IdleHandler");}synchronized (this) {mIdleHandlers.add(handler);}
}

从源码可以看出,addIdleHandler() 方法会将传入的 IdleHandler 实例添加到 mIdleHandlers 列表中。mIdleHandlers 是一个 ArrayList<IdleHandler> 类型的列表,用于存储所有添加的 IdleHandler

3. 消息队列空闲状态的判断

Looper 在从 MessageQueue 中取出消息时,会调用 MessageQueue 的 next() 方法。next() 方法会判断消息队列是否空闲,以下是 next() 方法的部分源码:

// MessageQueue.java
Message next() {// ... 其他代码 ...int nextPollTimeoutMillis = 0;for (;;) {// ... 其他代码 ...nativePollOnce(ptr, nextPollTimeoutMillis);synchronized (this) {// ... 其他代码 ...// 获取队列中的下一条消息Message msg = mMessages;if (msg != null && msg.target == null) {// 如果消息没有目标 Handler,继续查找下一条消息do {prevMsg = msg;msg = msg.next;} while (msg != null && !msg.isAsynchronous());}if (msg != null) {if (now < msg.when) {// 如果消息还未到执行时间,计算需要等待的时间nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);} else {// 消息可以执行,从队列中移除该消息mBlocked = false;if (prevMsg != null) {prevMsg.next = msg.next;} else {mMessages = msg.next;}msg.next = null;if (DEBUG) Log.v(TAG, "Returning message: " + msg);msg.markInUse();return msg;}} else {// 队列中没有消息,设置为无限期等待nextPollTimeoutMillis = -1;}// ... 其他代码 ...// 如果队列中没有消息或者下一条消息还未到执行时间,认为队列空闲if (pendingIdleHandlerCount < 0&& (mMessages == null || now < mMessages.when)) {pendingIdleHandlerCount = mIdleHandlers.size();}if (pendingIdleHandlerCount <= 0) {// 没有 IdleHandler 或者队列不空闲,继续等待mBlocked = true;continue;}// ... 其他代码 ...}// ... 其他代码 ...}
}

从源码可以看出,当队列中没有消息或者下一条消息的执行时间还未到时,MessageQueue 会认为队列处于空闲状态,并开始处理 IdleHandler

4. IdleHandler 的执行

当 MessageQueue 处于空闲状态时,会在 next() 方法中依次调用存储在 mIdleHandlers 列表中的所有 IdleHandler 的 queueIdle() 方法。以下是相关源码:

// MessageQueue.java
Message next() {// ... 其他代码 ...int pendingIdleHandlerCount = -1;for (;;) {// ... 其他代码 ...if (pendingIdleHandlerCount < 0&& (mMessages == null || now < mMessages.when)) {pendingIdleHandlerCount = mIdleHandlers.size();}if (pendingIdleHandlerCount <= 0) {// 没有 IdleHandler 或者队列不空闲,继续等待mBlocked = true;continue;}if (mPendingIdleHandlers == null) {mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];}mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);}// 执行 IdleHandlerfor (int i = 0; i < pendingIdleHandlerCount; i++) {final IdleHandler idler = mPendingIdleHandlers[i];mPendingIdleHandlers[i] = null; // 防止内存泄漏boolean keep = false;try {keep = idler.queueIdle();} catch (Throwable t) {Log.wtf(TAG, "IdleHandler threw exception", t);}if (!keep) {synchronized (this) {mIdleHandlers.remove(idler);}}}// ... 其他代码 ...return null;
}

从源码可以看出,MessageQueue 会将 mIdleHandlers 列表中的 IdleHandler 复制到 mPendingIdleHandlers 数组中,然后依次调用每个 IdleHandler 的 queueIdle() 方法。根据 queueIdle() 方法的返回值决定是否保留该 IdleHandler

  • 如果返回 true,则该 IdleHandler 会保留在 mIdleHandlers 列表中,下次消息队列空闲时会再次调用。
  • 如果返回 false,则该 IdleHandler 会从 mIdleHandlers 列表中移除。

总结

   IdleHandler 是 Android 消息机制中的一个重要特性,它允许开发者在消息队列空闲时执行特定任务。其工作原理主要包括:通过 addIdleHandler() 方法将 IdleHandler 添加到 MessageQueue 的 mIdleHandlers 列表中;Looper 在从 MessageQueue 中取出消息时,MessageQueue 的 next() 方法会判断队列是否空闲;当队列空闲时,会依次调用 mIdleHandlers 列表中的所有 IdleHandler 的 queueIdle() 方法,并根据返回值决定是否保留该 IdleHandler。通过这种方式,IdleHandler 可以在不影响主线程正常消息处理的前提下,执行一些低优先级的任务,从而优化应用的性能。

二、IntentService的工作原理

IntentService 是 Android 中的一个特殊服务,继承自 Service 类,它结合了 Service 和 HandlerThread 的特性,用于在后台线程执行异步任务,并且在任务完成后自动停止服务。以下详细介绍其工作原理。

1. 继承关系与构造函数

IntentService 继承自 Service,这意味着它拥有 Service 的生命周期方法。当创建 IntentService 的子类时,必须实现一个构造函数并调用父类的构造函数,传入一个用于标识该服务的名称。这个名称主要用于日志记录和调试。

import android.app.IntentService;
import android.content.Intent;public class MyIntentService extends IntentService {public MyIntentService() {super("MyIntentService");}@Overrideprotected void onHandleIntent(Intent intent) {// 处理传入的 Intent}
}

2. 内部的 HandlerThread

在 IntentService 的构造函数被调用后,它会创建一个 HandlerThreadHandlerThread 是一个带有 Looper 的线程,这使得它可以处理消息队列。IntentService 利用这个 HandlerThread 来执行后台任务,避免在主线程中执行耗时操作导致界面卡顿。

// IntentService.java 部分源码
public IntentService(String name) {super();mName = name;
}@Override
public void onCreate() {super.onCreate();HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");thread.start();mServiceLooper = thread.getLooper();mServiceHandler = new ServiceHandler(mServiceLooper);
}

3. ServiceHandler 与消息处理

IntentService 创建了一个 ServiceHandler 类,它继承自 Handler,并使用 HandlerThread 的 Looper 来处理消息。当有新的 Intent 被发送到 IntentService 时,onStartCommand 方法会将这个 Intent 封装成一个消息发送给 ServiceHandler

// IntentService.java 部分源码
private final class ServiceHandler extends Handler {public ServiceHandler(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message msg) {onHandleIntent((Intent)msg.obj);stopSelf(msg.arg1);}
}@Override
public int onStartCommand(Intent intent, int flags, int startId) {Message msg = mServiceHandler.obtainMessage();msg.arg1 = startId;msg.obj = intent;mServiceHandler.sendMessage(msg);return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

4. onHandleIntent 方法

ServiceHandler 接收到消息后,会调用 onHandleIntent 方法,并将 Intent 作为参数传递进去。开发者需要在 onHandleIntent 方法中实现具体的异步任务逻辑。这个方法运行在 HandlerThread 的线程中,因此可以执行耗时操作。

@Override
protected void onHandleIntent(Intent intent) {// 执行耗时任务,例如网络请求、文件读写等if (intent != null) {String action = intent.getAction();if (ACTION_FOO.equals(action)) {// 处理特定的操作}}
}

5. 任务完成后自动停止服务

当 onHandleIntent 方法执行完毕后,ServiceHandler 会调用 stopSelf(int startId) 方法来停止服务。startId 是一个唯一标识,用于确保只有当所有的 Intent 都被处理完毕后才停止服务。如果在处理过程中有新的 Intent 被发送进来,IntentService 会继续处理这些新的 Intent,直到所有任务都完成。

6. 总结

  • 创建 HandlerThread:在 onCreate 方法中创建一个 HandlerThread,并启动它,获取其 Looper
  • 创建 ServiceHandler:使用 HandlerThread 的 Looper 创建 ServiceHandler,用于处理消息。
  • 接收 Intent:在 onStartCommand 方法中,将 Intent 封装成消息并通过 ServiceHandler 发送出去。
  • 处理 IntentServiceHandler 接收到消息后,调用 onHandleIntent 方法处理 Intent
  • 停止服务:在 onHandleIntent 方法处理完成后,调用 stopSelf(int startId) 方法停止服务。
  • 销毁服务:在 onDestroy 方法中,停止 HandlerThread 的 Looper

通过这种方式,IntentService 提供了一种简单方便的方式来在后台线程执行异步任务,并且在任务完成后自动清理资源。

http://www.xdnf.cn/news/127387.html

相关文章:

  • 动手试一试 Spring Boot默认缓存管理
  • 中央对齐模式1 2与更新中断
  • Apifox 4月更新|Apifox在线文档支持LLMs.txt、评论支持使用@提及成员、支持为团队配置「IP 允许访问名单」
  • 使用setGraphicsEffect重新设置阴影导致程序崩溃的问题
  • SAP SuccessFactors Recruiting and Onboarding The Comprehensive Guide
  • 【oql】spark thriftserver内存溢出,使用oql查询导致oom的sql
  • 覆盖纸(Overlay Paper):装饰材料领域的“隐形冠军”
  • 每日一练(4~24):互质的数【省模拟赛】
  • 【python】解释builtin.py函数为何全是pass
  • Kaamel白皮书:Model Context Protocol (MCP) 隐私安全最佳实践
  • AGP8+ fullMode 完全模式混淆闪退
  • MAC地址攻击和ARP攻击的原理及解决方法
  • nodejs导入文件模块和导入文件夹
  • 研0调研入门
  • 【Vue3 实战】插槽封装与懒加载
  • LJF-Framework 第14章 LjfSecurity适配SpringSecurity
  • springcloud-openfeign
  • 使用钉钉机器人推送系统内部的ERP停机维护公告
  • 微信小程序 tabbar底部导航栏
  • 传统的图像压缩技术(二)
  • mysql——索引事务和JDBC编程
  • 【C++基础知识】namespace前加 inline
  • 低代码平台开发胎压监测APP
  • 【MySQL数据库】表的增删改查
  • C++智能指针上
  • 如何在Spring Boot中禁用Actuator端点安全性
  • containerd 配置代理
  • 生成随机验证码-解析与优化
  • 扩张尺度张量填充方式
  • HTML字符实体和转义字符串