CountDownTimer:在 Activity、ViewModel 或单独的 class 中?

CountDownTimer : In Activity, ViewModel or separate class?

我想创建一个 CountdownTimer 来触发更新 UI 的事件(触发弹出窗口、启动动画等)。

我想知道如何清理,这是我的假设和原因:

  1. 一个单独的组件EventCountdownTimer。然后我可以使用 LifecycleObserver,但我想知道如何将信息传回 activity(我尝试扩展 CountdownTimer 并在 activity 中使用它,但我有错误,无法编译)
  2. Activity 本身中,它是最简单的,但我不确定它属于那里,因为它不是 UI 组件,我无法从 LifecycleObserver 中受益
  3. ViewModel。我认为它与 activity 相关并且 CountdownTimer 有点逻辑数据,它应该放在这里,但这意味着还要观察 activity 的生命周期,并持有任何 Activity ViewModel 中的相关字段是不好的做法。

您认为最好的选择是什么?为什么?

在 MVVM 模式中,您可以在 ViewModel 中观察到一个 LiveData,UI 将观察到它,并且在值更改时您会相应地更新 UI。可观察值如何改变值,这就是您的业务逻辑,所有这些都应该在您的 ViewModel 中或单独的组件中,ViewModel 将使用这些组件来更新可观察状态。

这将允许您将 UI 与业务逻辑分开,作为您可观察到的业务逻辑,作为两者之间的通信桥梁,而 ViewModel 对 UI 中发生的事情一无所知。简而言之,它只执行它被告知要执行的内容并更新正在观察的变量,然后在 UI 中发生的是 UI 责任,这样你就可以清楚地分离关注点.

A separate component "EventCountdownTimer"

在我看来,这是您可能拥有的最佳实施方式。为了将信息传回您的 activity,您可以考虑使用如下所示的界面。

public interface TimerListener {
    void onTimerResponse(String response);
}

修改您的 EventCountdownTimer 以拥有一个将 TimerListener 作为参数的构造函数,并覆盖 activity 中的 onTimerResponse 方法。例如,现在从您的 EventCountdownTimer 尝试与您的 activity 通信并发送一条消息时,您可能只调用函数 onTimerResponse(msgToDeliver)

因此您的 EventCountdownTimer 应该看起来像这样。

public class EventCountdownTimer {
    public static Context context;
    public static TimerListener listener;

    public EventCountdownTimer(Context context, TimerListener listener) {
        this.context = context;
        this.listener = listener;
    }

    public startCountdown() {
        // Start the count down here
        // ... Other code

        // When its time to post some update to your activity
        listener.onTimerResponse(msgToDeliver);
    }
}

然后从您的 activity 中初始化 EventCountdownTimer,如下所示。

EventCountdownTimer timer = new EventCountdownTimer(this, new TimerListener() {
    @Override
    public void onTimerResponse(String message) {
        // Do something with the message data 
        // Update your UI maybe
    }
});

我认为您已经提供了不选择您提到的其他选项的充分理由。

Google 解决方案:see it on github

/**
 * A ViewModel used for the {@link ChronoActivity3}.
 */
public class LiveDataTimerViewModel extends ViewModel {

    private static final int ONE_SECOND = 1000;

    private MutableLiveData<Long> mElapsedTime = new MutableLiveData<>();

    private long mInitialTime;
    private final Timer timer;

    public LiveDataTimerViewModel() {
        mInitialTime = SystemClock.elapsedRealtime();
        timer = new Timer();

        // Update the elapsed time every second.
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                final long newValue = (SystemClock.elapsedRealtime() - mInitialTime) / 1000;
                // setValue() cannot be called from a background thread so post to main thread.
                mElapsedTime.postValue(newValue);
            }
        }, ONE_SECOND, ONE_SECOND);

    }

    public LiveData<Long> getElapsedTime() {
        return mElapsedTime;
    }

    @Override
    protected void onCleared() {
        super.onCleared();
        timer.cancel();
    }
}