RicardoJiang / android-architecture

追求android架构更佳实践~
MIT License
323 stars 48 forks source link

单value的viewEvents无法支持多维度event #1

Closed yiyayiyayo closed 2 years ago

yiyayiyayo commented 2 years ago

如NetworkViewModel中局部请求后立即点home切后台, 等网络请求成功后再切回前台, ShowToast事件覆盖DismissLoadingDialog导致loading dialog未被dismiss

RicardoJiang commented 2 years ago

谢谢提醒,的确有这个问题,已修复。 添加了SingleLiveEvents,将所有事件通过列表存储,如下所示

class FlowViewModel : ViewModel() {
    private val _viewEvents: SingleLiveEvents<NetworkViewEvent> = SingleLiveEvents()
    val viewEvents = _viewEvents.asLiveData()

    private fun partRequest() {
        viewModelScope.launch {
            flow {
                delay(2000)
                emit("点赞成功")
            }.onStart {
                _viewEvents.setEvent(NetworkViewEvent.ShowLoadingDialog)
            }.onEach {
                _viewEvents.setEvent(
                    NetworkViewEvent.DismissLoadingDialog, NetworkViewEvent.ShowToast(it)
                )
                _viewStates.setState { copy(content = it) }
            }.commonCatch {
                _viewEvents.setEvent(NetworkViewEvent.DismissLoadingDialog)
            }.collect()
        }
    }
}
yiyayiyayo commented 2 years ago

谢谢提醒,的确有这个问题,已修复。 添加了SingleLiveEvents,将所有事件通过列表存储,如下所示

class FlowViewModel : ViewModel() {
    private val _viewEvents: SingleLiveEvents<NetworkViewEvent> = SingleLiveEvents()
    val viewEvents = _viewEvents.asLiveData()

    private fun partRequest() {
        viewModelScope.launch {
            flow {
                delay(2000)
                emit("点赞成功")
            }.onStart {
                _viewEvents.setEvent(NetworkViewEvent.ShowLoadingDialog)
            }.onEach {
                _viewEvents.setEvent(
                    NetworkViewEvent.DismissLoadingDialog, NetworkViewEvent.ShowToast(it)
                )
                _viewStates.setState { copy(content = it) }
            }.commonCatch {
                _viewEvents.setEvent(NetworkViewEvent.DismissLoadingDialog)
            }.collect()
        }
    }
}

我觉得多处在设置_viewEvents时还是会存在覆盖问题的哈

RicardoJiang commented 2 years ago

恩,说的对,可以将event存储在List中,在observer中清除,如果一直在后台,则会累计不会被覆盖 因为都在主线程,也没有线程安全问题,我晚点提下

class SingleLiveEvents<T> : MutableLiveData<List<T>>() {
    private val pending = AtomicBoolean(false)
    private val eventList = mutableListOf<List<T>>()

    @MainThread
    override fun observe(owner: LifecycleOwner, observer: Observer<in List<T>>) {
        super.observe(owner, { t ->
            if (pending.compareAndSet(true, false)) {
                eventList.clear()
                observer.onChanged(t)
            }
        })
    }

    @MainThread
    override fun setValue(t: List<T>?) {
        pending.set(true)
        t?.let {
            eventList.add(it)
        }
        val list = eventList.flatten()
        super.setValue(list)
    }
}
RicardoJiang commented 2 years ago

问题已修复~

luckyAF commented 2 years ago

额 我的处理是 hideLoading 里面传一个message message有内容就toast一下