Let Every Observer Only Receive *new* Livedata Upon Subscribing/observing
Whenever you call .observe() on LiveData, the Observer receives the last value of that LiveData. This may be useful in some cases, but not in mine. Whenever I call .observe(), I
Solution 1:
UPDATE 2021:
Using the coroutines library and Flow it is now very easy to achieve this by implementing Channels
:
MainActivity
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
classMainActivity : AppCompatActivity() {
privatelateinitvar viewModel: MainViewModel
privatelateinitvar binding: ActivityMainBinding
overridefunonCreate(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()
}
}
}
}
}
}
MainViewModel
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
classMainViewModel : ViewModel() {
sealedclassMyEvent{
dataclassErrorEvent(val message: String): MyEvent()
}
privateval eventChannel = Channel<MyEvent>()
val eventFlow = eventChannel.receiveAsFlow()
funtriggerEvent() = viewModelScope.launch {
eventChannel.send(MyEvent.ErrorEvent("This is an error"))
}
}
Solution 2:
For me problem was solved with this:
Event wrapper class to keep event related data(Copy from google samples)
publicclassEvent<T> {
private T mContent;
privateboolean hasBeenHandled = false;
publicEvent( T content) {
if (content == null) {
thrownewIllegalArgumentException("null values in Event are not allowed.");
}
mContent = content;
}
@Nullablepublic T getContentIfNotHandled() {
if (hasBeenHandled) {
returnnull;
} else {
hasBeenHandled = true;
return mContent;
}
}
publicbooleanhasBeenHandled() {
return hasBeenHandled;
}
}
Next, i create event observer class, that handles data checks(null, etc):
publicclassEventObserver<T> implementsObserver<Event<T>> {
@OverridepublicvoidonChanged(Event<T> tEvent) {
if (tEvent != null && !tEvent.hasBeenHandled())
onEvent(tEvent.getContentIfNotHandled());
}
protectedvoidonEvent(@NonNull T content) {}
}
And, event handler class, to simplify access from viewmodel:
publicclassEventHandler<T> {
privateMutableLiveData<Event<T>> liveEvent = newMutableLiveData<>();
publicvoidobserve(@NonNull LifecycleOwner owner, @NonNull EventObserver<T> observer){
liveEvent.observe(owner, observer);
}
publicvoidcreate(T content) {
liveEvent.setValue(newEvent<>(content));
}
}
Example:
In ViewModel.class:
privateEventHandler<Boolean> swipeEventHandler = newEventHandler<>();
publicEventHandler<Boolean> getSwipeEventHandler() {
return swipeEventHandler;
}
In Activity/Fragment:
Start observing:
viewModel.getSwipeEventHandler()
.observe(
getViewLifecycleOwner(),
new EventObserver<Boolean>() {
@Override
protected void onEvent(@NonNull Boolean content) {
if(content)confirmDelete(modifier);
}
});
Create event:
viewModel.getSwipeEventHandler().create(true);
Post a Comment for "Let Every Observer Only Receive *new* Livedata Upon Subscribing/observing"