CountDownTimer:在 Activity、ViewModel 或单独的 class 中?
CountDownTimer : In Activity, ViewModel or separate class?
我想创建一个 CountdownTimer
来触发更新 UI 的事件(触发弹出窗口、启动动画等)。
我想知道如何清理,这是我的假设和原因:
- 一个单独的组件
EventCountdownTimer
。然后我可以使用 LifecycleObserver
,但我想知道如何将信息传回 activity(我尝试扩展 CountdownTimer
并在 activity 中使用它,但我有错误,无法编译)
- 在
Activity
本身中,它是最简单的,但我不确定它属于那里,因为它不是 UI 组件,我无法从 LifecycleObserver
中受益
- 在
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();
}
}
我想创建一个 CountdownTimer
来触发更新 UI 的事件(触发弹出窗口、启动动画等)。
我想知道如何清理,这是我的假设和原因:
- 一个单独的组件
EventCountdownTimer
。然后我可以使用LifecycleObserver
,但我想知道如何将信息传回 activity(我尝试扩展CountdownTimer
并在 activity 中使用它,但我有错误,无法编译) - 在
Activity
本身中,它是最简单的,但我不确定它属于那里,因为它不是 UI 组件,我无法从LifecycleObserver
中受益 - 在
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();
}
}