如何定时更新ViewModel/LiveData且避免应用后台时执行高成本计算
实现方案
核心思路
利用组件生命周期的可见性回调,在用户可见时启动定时任务,不可见时主动停止任务,从根源上避免后台执行高成本计算。
具体实现(按页面可见性启停,适配单页面使用场景)
1. 改造ViewModel
暴露定时器启停方法,增加多观察者兼容逻辑,同时修复原有代码的无效判断问题:
public class EventDatesViewModel extends AndroidViewModel { private final MutableLiveData<String> timeToEvent = new MutableLiveData<>(); private final Handler handler = new Handler(); private boolean isTimerRunning = false; // 多观察者计数,避免单个页面退出就停掉所有页面的计时 private int observerCount = 0; private final Runnable runnable = new Runnable() { @Override public void run() { new Thread(() -> calculateTimeToEvent()).start(); handler.postDelayed(this, 10000); } }; public EventDatesViewModel(@NonNull Application application) { super(application); } public LiveData<String> getTimeToEvent() { // 原有判断无效,timeToEvent已经初始化,永远不为null return timeToEvent; } // 对外暴露启动计时方法 public void startTimer() { observerCount++; if (isTimerRunning) { return; } isTimerRunning = true; // 立刻执行一次计算 new Thread(this::calculateTimeToEvent).start(); handler.postDelayed(runnable, 10000); } // 对外暴露停止计时方法 public void stopTimer() { observerCount--; if (observerCount > 0) { return; } isTimerRunning = false; handler.removeCallbacks(runnable); } private void calculateTimeToEvent() { // 原有计算逻辑不变 timeToEvent.postValue(t); } @Override protected void onCleared() { super.onCleared(); handler.removeCallbacks(runnable); } }
2. 改造Fragment
绑定Fragment生命周期启停定时器:
public class GarbageFragment extends Fragment { private EventDatesViewModel model; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.fragment_garbage, container, false); model = new ViewModelProvider(requireActivity(), new ViewModelProvider.AndroidViewModelFactory(requireActivity().getApplication())).get(EventDatesViewModel.class); model.getTimeToEvent().observe(this, timeToEvent -> { ((TextView)root.findViewById(R.id.textTimeToEvent)).setText(timeToEvent); }); return root; } // 页面可见时启动计时 @Override public void onStart() { super.onStart(); model.startTimer(); } // 页面不可见(退后台、息屏、切页面)时停止计时 @Override public void onStop() { super.onStop(); model.stopTimer(); } }
可选实现(按应用前后台启停,适配多页面共用ViewModel场景)
如果希望只要应用在前台就运行倒计时,不管当前在哪个页面,可以使用ProcessLifecycleOwner做全局监听:
- 先添加Module级依赖:
dependencies { implementation "androidx.lifecycle:lifecycle-process:2.6.2" }
- 在ViewModel构造方法中注册全局生命周期观察者,无需在每个页面单独调用启停方法即可自动适配应用前后台状态。
内容的提问来源于stack exchange,提问作者AndreKR
相关产品推荐
相关产品推荐

