Android开发中Activity停止时终止LiveData关联定时任务的正确方案
问题解答
一、是否存在内存泄漏风险?
存在明确的内存泄漏风险,问题根源如下:
- 你在ViewModel构造方法中创建的
Timer是局部变量,没有保留实例引用,无法主动终止定时器运行。Timer启动后会持有内部TimerTask的引用,而匿名内部类TimerTask默认持有外部ViewModel实例的引用,只要定时器还在调度运行,ViewModel就无法被GC回收,哪怕其关联的Activity已经销毁。 - 你使用了
static修饰的counter变量,所有ViewModel实例会共用这一个计数变量,多次启动Activity生成多个定时器时会出现计数混乱。 - Activity正常销毁(非配置变更类销毁,如用户按返回键退出)后,旧定时器没有终止,重启Activity会创建新的ViewModel同时启动新定时器,就会出现多定时器同时运行的问题,也会进一步加剧内存泄漏。
二、停止任务的正确实现方式
核心逻辑是利用ViewModel的onCleared生命周期回调,在关联的页面真正销毁时主动终止定时器,修改方案如下:
- 将
Timer改为ViewModel的成员变量,保留实例引用用于后续取消操作 - 去掉
counter的static修饰符,改为实例成员变量,避免多实例共享计数 - 重写ViewModel的
onCleared()方法,在回调中终止定时器并释放资源
修改后的MainActivityViewModel代码:
public class MainActivityViewModel extends ViewModel { private MutableLiveData<Integer> mutableLiveData = new MainActivityLiveData<>(); private static final int BEGIN_AFTER = 1000, INTERVAL = 5000; // 改为实例成员,避免多实例共用 private int counter = 0; // 保存Timer实例作为成员变量 private Timer timer; public MainActivityViewModel() { startTimer(); } private void startTimer() { timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { Log.d("mylog", timer.toString() + " " + ++counter); mutableLiveData.postValue(counter); } }, BEGIN_AFTER, INTERVAL); } public MutableLiveData<Integer> getLiveData() { return mutableLiveData; } // ViewModel销毁时回调,终止定时器 @Override protected void onCleared() { super.onCleared(); if (timer != null) { timer.cancel(); timer.purge(); timer = null; } } }
补充说明
- 如果你的定时器需求是不受页面生命周期影响、后台也要持续运行,不要在ViewModel中实现,应改用WorkManager或前台服务实现。
- 上述修改后,配置变更(如屏幕旋转)导致的Activity重建不会触发ViewModel的
onCleared,定时器会继续运行,计数不会中断,符合ViewModel的设计定位。
内容的提问来源于stack exchange,提问作者barabash196
相关产品推荐
相关产品推荐

