自定义组件中用静态Runnable+WeakReference实现按需启停的轻量轮询,绑定生命周期避免泄漏,支持动态调整间隔,逻辑仅限主线程轻量检查并回调。

在自定义组件中用 Runnable 实现动态挂载的轻量级后台轮询,核心是「按需启停 + 组件生命周期绑定 + 无内存泄漏」。不依赖第三方库,纯 Android 原生 Handler + Runnable 即可达成。
绑定组件生命周期,避免内存泄漏
Runnable 持有外部类引用时容易导致 Activity/Fragment 泄漏。正确做法是:使用静态内部类 + WeakReference,且只在组件处于活跃状态(如 onResume)时 post,onPause 或 onDestroy 时移除:
- 定义静态 Runnable,通过 WeakReference 访问组件实例
- 在自定义 View / Fragment 的
onAttachedToWindow()或onResume()中调用handler.postDelayed(runnable, interval) - 在
onDetachedFromWindow()或onPause()中执行handler.removeCallbacks(runnable)
实现可动态启停与间隔调整
轮询不应写死周期,而应支持运行时修改。建议封装一个简易轮询控制器:
- 用一个 volatile boolean 标记是否启用(如
isPollingEnabled),每次执行前先校验 - 将 delay 时间抽为变量,在重启轮询时传入新值,无需重建 Handler
- 提供
startPolling(long intervalMs)和stopPolling()方法,内部统一管理 post 状态
轻量设计:避免重复 post 与主线程阻塞
轮询逻辑必须轻量——仅做必要检查或触发回调,耗时操作交由子线程或协程处理:
- Runnable 内不要做网络请求、数据库读写等耗时操作;可仅检查本地标记位、通知监听器、或 post 到子线程执行
- 确保每次执行完都重新 post 自身(用
handler.postDelayed(this, interval)),但前提是未被移除且启用中 - 若轮询任务本身可能延时(如等待异步结果),建议改用一次性 post + 回调后手动触发下一次,而非固定间隔盲 post
在自定义 View 中的典型集成示例
比如一个带状态指示的自定义按钮,需每 3 秒检查一次服务连接状态:
- 在 View 构造中初始化 Handler(绑定主线程 Looper)和静态 Runnable
- 重写
onAttachedToWindow()启动轮询;重写onDetachedFromWindow()停止 - 轮询体中调用
checkServiceStatus()(轻量方法),再根据结果更新 UI 或触发监听器 - 对外暴露
setPollingInterval(int ms)和enablePolling(boolean),实时生效
不复杂但容易忽略细节:Handler 必须关联主线程 Looper,Runnable 必须可被安全移除,轮询动作要真正“按需”存在——组件不可见或不需要时,它就该安静待命。

















