architecture-samples icon indicating copy to clipboard operation
architecture-samples copied to clipboard

'TO-DO added' message does not work properly

Open shaifulcse opened this issue 7 years ago • 1 comments

This message is shown only for the first added item. For the next items, it never comes.

Only happens for: todo-mvvm-databinding

git checkout todo-mvvm-databinding

shaifulcse avatar Feb 08 '18 01:02 shaifulcse

the problem in the todo-mvvm-databinding branch comes from the way the “TO-DO added” Snackbar message is triggered.

Why it only shows for the first added item In the todo-mvvm-databinding sample, the View layer observes a LiveData (or ObservableField) in the ViewModel for showing Snackbar messages, something like:

public final ObservableField<String> snackbarText = new ObservableField<>(); or

private final MutableLiveData<String> _snackbarText = new MutableLiveData<>(); LiveData<String> snackbarText = _snackbarText; The Snackbar is shown whenever snackbarText changes.

The problem: If the ViewModel sets the same value ("TO-DO added") twice in a row, ObservableField and LiveData won’t trigger the observer the second time because the value hasn’t actually changed.

So:

First item added → "TO-DO added" set → observer triggers → Snackbar shows.

Second item added → "TO-DO added" set again → no change detected → observer does nothing → Snackbar doesn’t show.

How to fix it Option 1 – Use a one-time event wrapper This is the recommended Android Architecture Components approach:

Create an Event class:

public class Event<T> { private final T content; private boolean hasBeenHandled = false;

public Event(T content) {
    this.content = content;
}

public T getContentIfNotHandled() {
    if (hasBeenHandled) return null;
    hasBeenHandled = true;
    return content;
}

public T peekContent() {
    return content;
}

} In the ViewModel:

private final MutableLiveData<Event<Integer>> _snackbarText = new MutableLiveData<>(); LiveData<Event<Integer>> snackbarText = _snackbarText;

void showTodoAddedMessage() { _snackbarText.setValue(new Event<>(R.string.todo_added)); } In the Activity/Fragment:

viewModel.snackbarText.observe(this, event -> { Integer messageRes = event.getContentIfNotHandled(); if (messageRes != null) { Snackbar.make(rootView, messageRes, Snackbar.LENGTH_SHORT).show(); } }); This way, every call to showTodoAddedMessage() emits a new Event object, even with the same message text.

Option 2 – Force value change If you don’t want an Event wrapper, you can “reset” the value before setting it again:

snackbarText.setValue(null); snackbarText.setValue("TO-DO added"); This works, but it’s hacky and not recommended for clean MVVM.

Why this only happens in todo-mvvm-databinding Other variants (like todo-mvp) often trigger Snackbars through direct view method calls in Presenters, which always run even with the same message. With Data Binding + LiveData/ObservableField, updates depend on value changes, so repeating the same value doesn’t trigger UI updates.

VaradGupta23 avatar Aug 08 '25 12:08 VaradGupta23