每当您在LiveData上调用.observe()
时,观察者都会收到该LiveData的最后一个值。在某些情况下这可能很有用,但在我的情况下却没有。
每当我调用.observe()
时,我都希望观察者仅接收将来的LiveData更改,而不希望接收.observe()
时它持有的值。
我可能有多个LiveData实例的观察者。我希望他们在发生时都能收到LiveData更新。
我希望每个LiveData更新仅由每个观察者使用一次。我认为这只是对第一个要求的重新表述,但我的头已经在旋转,我正在不确定。
在搜索这个问题时,我遇到了两种常见的方法:
将数据包装在LiveData<SingleEvent<Data>>
中,并检查此SingleEvent
类是否已被使用。
扩展MediatorLiveData
并在观察者已经收到事件的情况下使用查找映射
这些方法的示例可以在这里找到: https://gist.github.com/JoseAlcerreca/5b661f1800e1e654f07cc54fe87441af#gistcomment-2783677 https://gist.github.com/hadilq/f095120348a6a14251a02aca329f1845#file-liveevent-kt https://gist.github.com/JoseAlcerreca/5b661f1800e1e654f07cc54fe87441af#file-event-kt
不幸的是,这些示例都不能解决 all 的要求。大多数情况下,问题在于任何新的观察者在订阅后仍会收到最后一个LiveData值。这意味着,每当用户在屏幕之间导航时,就会一次又一次显示已经显示的Snackbar。
为了给您一些见解,我在说什么/我在编码什么:
我正在关注Android Architecture Componentns的LiveData MVVM设计:
Repository.delete()
RepositoryEvents
的存储库。因此,删除完成后,存储库会将其通知给ViewModel,而ViewModel会将其通知给ListFragment。
现在,当用户切换到第二个ListFragment时,将发生以下情况:
.observe()
已创建ViewModel并在存储库上调用.observe()
存储库将其当前的RepositoryEvent
发送到ViewModel
这里有一些简化的代码:
片段:
viewModel.dataEvents.observe(viewLifecycleOwner, Observer { showSnackbar() })
viewModel.deleteEntry()
ViewModel:
val dataEvents: LiveData<EntryListEvent> = Transformations.switchMap(repository.events, ::handleRepoEvent)
fun deleteEntry() = repository.deleteEntry()
private fun handleRepoEvent(event: RepositoryEvent): LiveData<EntryListEvent> {
// convert the repository event to an UI event
}
存储库:
private val _events = MutableLiveData<RepositoryEvent>()
val events: LiveData<RepositoryEvent>
get() = _events
fun deleteEntry() {
// delete it from database
_events.postValue(RepositoryEvent.OnDeleteSuccess)
}
答案 0 :(得分:1)
2021 年更新:
使用协程库和 Flow,现在很容易通过实现 Channels
来实现:
主活动
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.google.android.material.snackbar.Snackbar
import com.plcoding.kotlinchannels.databinding.ActivityMainBinding
import kotlinx.coroutines.flow.collect
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
binding.btnShowSnackbar.setOnClickListener {
viewModel.triggerEvent()
}
lifecycleScope.launchWhenStarted {
viewModel.eventFlow.collect { event ->
when(event) {
is MainViewModel.MyEvent.ErrorEvent -> {
Snackbar.make(binding.root, event.message, Snackbar.LENGTH_LONG).show()
}
}
}
}
}
}
主视图模型
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
class MainViewModel : ViewModel() {
sealed class MyEvent {
data class ErrorEvent(val message: String): MyEvent()
}
private val eventChannel = Channel<MyEvent>()
val eventFlow = eventChannel.receiveAsFlow()
fun triggerEvent() = viewModelScope.launch {
eventChannel.send(MyEvent.ErrorEvent("This is an error"))
}
}
答案 1 :(得分:0)
对我来说,问题已通过以下方式解决:
事件包装器类,用于保留与事件相关的数据(从Google示例中复制)
public class Event<T> {
private T mContent;
private boolean hasBeenHandled = false;
public Event( T content) {
if (content == null) {
throw new IllegalArgumentException("null values in Event are not allowed.");
}
mContent = content;
}
@Nullable
public T getContentIfNotHandled() {
if (hasBeenHandled) {
return null;
} else {
hasBeenHandled = true;
return mContent;
}
}
public boolean hasBeenHandled() {
return hasBeenHandled;
}
}
接下来,我创建事件观察器类,该类处理数据检查(null等):
public class EventObserver<T> implements Observer<Event<T>> {
@Override
public void onChanged(Event<T> tEvent) {
if (tEvent != null && !tEvent.hasBeenHandled())
onEvent(tEvent.getContentIfNotHandled());
}
protected void onEvent(@NonNull T content) {}
}
此外,事件处理程序类用于简化从viewmodel的访问:
public class EventHandler<T> {
private MutableLiveData<Event<T>> liveEvent = new MutableLiveData<>();
public void observe(@NonNull LifecycleOwner owner, @NonNull EventObserver<T> observer){
liveEvent.observe(owner, observer);
}
public void create(T content) {
liveEvent.setValue(new Event<>(content));
}
}
示例:
在ViewModel.class中:
private EventHandler<Boolean> swipeEventHandler = new EventHandler<>();
public EventHandler<Boolean> getSwipeEventHandler() {
return swipeEventHandler;
}
活动/片段中:
开始观察:
viewModel
.getSwipeEventHandler()
.observe(
getViewLifecycleOwner(),
new EventObserver<Boolean>() {
@Override
protected void onEvent(@NonNull Boolean content) {
if(content)confirmDelete(modifier);
}
});
创建事件:
viewModel.getSwipeEventHandler().create(true);