Search code examples
androiddata-bindingandroid-livedataandroid-binding-adapter

LiveData<String>.getValue() returns null although mPendingData holds correct value


I want to use a custom @BindingAdapter to set the text of a TextView using LiveData.

TextView:

<TextView
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:gravity="center"
       app:keyToText='@{viewmodel.getText("TI_001")}'/>

BindingAdapter:

@BindingAdapter("keyToText")
public static void setTextViewText(TextView tv, LiveData<String> data) {
    if (data == null || data.getValue() == null) {
        tv.setText(null);
    } else {
        tv.setText(data.getValue());
    }
}

Using the debugger, I already checked that the data object holds the correct value, which it does:

enter image description here

But unfortunately data.getValue() always returns null, so the text isn't set to the provided TextView.

Am I missing something? I really need this to work this way... hopefully.

UPDATE

The lifecycleowner is set to the binding as followed:

mBinding.setLifecycleOwner(this);

When I use

viewModel.getText("TI_001").observe(this, new Observer<String>() {
        @Override
        public void onChanged(@Nullable String s) {
            tv.setText(s);
        }
    });

I can read the value of observed LiveData without any problems.

UPDATE 2

Viewmodels getText method:

public LiveData<String> getText(String key){
    return textRepository.getText(key);
}

textRepository's getText method:

public LiveData<String> getText(String id){
    return textDao.findById(id);
}

And textDao's findById method:

@Query("SELECT text.text FROM text WHERE text.id LIKE :id")
LiveData<String> findById(String id);

Solution

  • I might have found a solution for my problem:

    @BindingAdapter("keyToText")
    public static void setTextViewText(TextView tv, LiveData<String> data) {
        if (data == null) {
            tv.setText(null);
        } else {
            data.observeForever(new Observer<String>() {
                @Override
                public void onChanged(@Nullable String s) {
                    tv.setText(data.getValue());
                    data.removeObserver(this);
                }
            });
        }
    }
    

    So I'm basically observing my LiveData only for the first onChanged event and removing the used observer right after setting the text.