Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: MVVM is it possible to display a message (toast/snackbar etc.) from the ViewModel

I want to know what is the best approach to display some sort of message in the view from the ViewModel. My ViewModel is making a POST call and "onResult" I want to pop up a message to the user containing a certain message.

This is my ViewModel:

public class RegisterViewModel extends ViewModel implements Observable {
.
.   
.
public void registerUser(PostUserRegDao postUserRegDao) {

    repository.executeRegistration(postUserRegDao).enqueue(new Callback<RegistratedUserDTO>() {
        @Override
        public void onResponse(Call<RegistratedUserDTO> call, Response<RegistratedUserDTO> response) {
            RegistratedUserDTO registratedUserDTO = response.body();
            /// here I want to set the message and send it to the Activity

            if (registratedUserDTO.getRegisterUserResultDTO().getError() != null) {

            }
        }

    });
}

And my Activity:

public class RegisterActivity extends BaseActivity {   

@Override
protected int layoutRes() {
    return R.layout.activity_register;
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    AndroidInjection.inject(this);
    super.onCreate(savedInstanceState);

    ActivityRegisterBinding binding = DataBindingUtil.setContentView(this, layoutRes());
    binding.setViewModel(mRegisterViewModel);       
}

What would the best approach be in this case?

like image 911
user3182266 Avatar asked Nov 26 '18 15:11

user3182266


1 Answers

We can use a SingleLiveEvent class as a solution. But it is a LiveData that will only send an update once. In my personal experience, using an Event Wrapper class with MutableLiveData is the best solution.

Here is a simple code sample.

Step 1 : Create an Event class (this is a boilerplate code you can reuse for any android project).

open class Event<out T>(private val content: T) {

var hasBeenHandled = false
    private set // Allow external read but not write

/**
 * Returns the content and prevents its use again.
 */
fun getContentIfNotHandled(): T? {
    return if (hasBeenHandled) {
        null
    } else {
        hasBeenHandled = true
        content
    }
}

/**
 * Returns the content, even if it's already been handled.
 */
fun peekContent(): T = content

}

Step 2 : At the top of your View Model class, define a MutableLiveData with wrapper (I used a String here, but you can use your required data type), and a corresponding live data for encapsulation.

private val statusMessage = MutableLiveData<Event<String>>()

val message : LiveData<Event<String>>
  get() = statusMessage

Step 3 : You can update the status message within the functions of the ViewModel like this:

statusMessage.value = Event("User Updated Successfully")

Step 4 :

Write code to observe the live data from the View (activity or fragment)

 yourViewModel.message.observe(this, Observer {
     it.getContentIfNotHandled()?.let {
         Toast.makeText(this, it, Toast.LENGTH_LONG).show()
     }
 })
like image 134
AlexM Avatar answered Sep 21 '22 17:09

AlexM