LIVEDATA的Lateinit var

发布于 2025-02-06 18:32:49 字数 2197 浏览 2 评论 0原文

在我的ViewModel中,我有一个LateInit var可以容纳一些Livedata。初始化此变量的方式取决于数据和当前日期。无法在SQL中做到这一点。这是ViewModel:

class MainViewModel {
    lateinit var timeStamps: LiveData<List<TimeStamp>>

    init {
        viewModelScope.launch {
            val db = RoomDB.getInstance(application).timeStampDao()
            val lastTimeStamp = db.getLast()
            if (lastTimeStamp == null
                || (lastTimeStamp.instant < setToStartOfDay(Calendar.getInstance()).timeInMillis)
                && lastTimeStamp.action == ACTION.END_WORK) {
                timeStamps = db.getAllAfterLive(Calendar.getInstance().timeInMillis)
            } else {
                db.getLastAction(ACTION.START_WORK)?.let { lastStartWork ->
                    val startOfDay = setToStartOfDay(initCalendar(lastStartWork.instant)).timeInMillis
                    db.getFirstActionAfter(ACTION.START_WORK, startOfDay)?.let {
                        timeStamps = db.getAllAfterLive(it.instant)
                    }
                }
            }

在我的活动中,我在这里访问timestamps

override fun onCreate(savedInstanceState: Bundle?) {

    viewModel.timeStamps.observe(this) { list -> recordsAdapter.submitList(list) }

这导致notialialized propertyAccessexecception:onCreate运行速度要比timestamps平行启动更快。

我通过引入另一个lateInit var来解决此问题:

class MainViewModel {
    lateinit var timeStamps: LiveData<List<TimeStamp>>
    lateinit var timeStampsInitializedCallback: () -> Unit

    init {
        viewModelScope.launch {
            // inspect the data and initialize timeStamps
            timeStampsInitializedCallback()
        }

我以increate的初始化:

override fun onCreate(savedInstanceState: Bundle?) {

    viewModel.timeStampsInitializedCallback = {
        viewModel.timeStamps.observe(this) { list -> recordsAdapter.submitList(list) }
    }

这有效,但它引入了竞赛条件。如果时间戳的初始化在初始化回调之前出乎意料地完成,我会得到另一个notialialized propertyaccessexception,然后回到我开始的地方。

如何改进此代码?

In my ViewModel I have a lateinit var to hold some LiveData. The way this variable is initialized depends on the data and the current date. Can't do it in SQL. This is the ViewModel:

class MainViewModel {
    lateinit var timeStamps: LiveData<List<TimeStamp>>

    init {
        viewModelScope.launch {
            val db = RoomDB.getInstance(application).timeStampDao()
            val lastTimeStamp = db.getLast()
            if (lastTimeStamp == null
                || (lastTimeStamp.instant < setToStartOfDay(Calendar.getInstance()).timeInMillis)
                && lastTimeStamp.action == ACTION.END_WORK) {
                timeStamps = db.getAllAfterLive(Calendar.getInstance().timeInMillis)
            } else {
                db.getLastAction(ACTION.START_WORK)?.let { lastStartWork ->
                    val startOfDay = setToStartOfDay(initCalendar(lastStartWork.instant)).timeInMillis
                    db.getFirstActionAfter(ACTION.START_WORK, startOfDay)?.let {
                        timeStamps = db.getAllAfterLive(it.instant)
                    }
                }
            }

Here I access timeStamps in my Activity:

override fun onCreate(savedInstanceState: Bundle?) {

    viewModel.timeStamps.observe(this) { list -> recordsAdapter.submitList(list) }

This leads to a UninitializedPropertyAccessException: onCreate runs faster than the timeStamps initialization launched in parallel.

I fixed this by introducing another lateinit var for a callback:

class MainViewModel {
    lateinit var timeStamps: LiveData<List<TimeStamp>>
    lateinit var timeStampsInitializedCallback: () -> Unit

    init {
        viewModelScope.launch {
            // inspect the data and initialize timeStamps
            timeStampsInitializedCallback()
        }

which I initialize in onCreate:

override fun onCreate(savedInstanceState: Bundle?) {

    viewModel.timeStampsInitializedCallback = {
        viewModel.timeStamps.observe(this) { list -> recordsAdapter.submitList(list) }
    }

This works, but it introduces a race condition. Should the initialization for timeStamps unexpectedly finish before the callback is initialized, I'd get another UninitializedPropertyAccessException and be back where I started.

How can I improve this code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

黑白记忆 2025-02-13 18:32:49

您还可以使用 livedatabuilder函数:

class MainViewModel {
    val timeStamps: LiveData<List<TimeStamp>> = liveData {
        // inspect the data and initialize timeStamps
        emit(timeStamps) // emit list of TimeStamps
        emitSource(liveData) // emit another LiveData
    }

}

// in Activity

override fun onCreate(savedInstanceState: Bundle?) {
    viewModel.timeStamps.observe(this) { list -> recordsAdapter.submitList(list) }
}

livedata代码块在livedata变得活跃时开始执行,并在可配置超时后自动取消,当livedata变得不活跃时。

You can also use liveData builder function:

class MainViewModel {
    val timeStamps: LiveData<List<TimeStamp>> = liveData {
        // inspect the data and initialize timeStamps
        emit(timeStamps) // emit list of TimeStamps
        emitSource(liveData) // emit another LiveData
    }

}

// in Activity

override fun onCreate(savedInstanceState: Bundle?) {
    viewModel.timeStamps.observe(this) { list -> recordsAdapter.submitList(list) }
}

The liveData code block starts executing when LiveData becomes active and is automatically canceled after a configurable timeout when the LiveData becomes inactive.

软糖 2025-02-13 18:32:49

最简单的选项似乎mutableLivedata

class MainViewModel {
    private val _timeStamps = MutableLiveData<List<TimeStamp>>()
    val timeStamps: LiveData<List<TimeStamp>> = _timeStamps

    init {
        viewModelScope.launch {
            // inspect the data and set a value on _timeStamps
        }

取决于Coroutine的所作所为,可能还有其他选项(例如,flow> flow> flow上的aslived> aslivedata()中级属性)。

The simplest option seems like MutableLiveData:

class MainViewModel {
    private val _timeStamps = MutableLiveData<List<TimeStamp>>()
    val timeStamps: LiveData<List<TimeStamp>> = _timeStamps

    init {
        viewModelScope.launch {
            // inspect the data and set a value on _timeStamps
        }

Depending on what the coroutine is doing, there may be other options (e.g., asLiveData() on a Flow, MediatorLiveData).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文