Skip to content Skip to sidebar Skip to footer

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"