Alexander Farber
Alexander Farber

Reputation: 22958

How to use LiveData, when the DAO method requires a changing parameter?

In a dictionary app using Room to store words I have a Fragment with a TextField.

When the user enters a word into the TextField, I am extracting the text and send it to a JobIntentService, which then calls the DAO method synchronously on its own thread:

@Dao
public interface MyDao {
    @Query("SELECT 1 FROM dictionary WHERE word = :word")
    int findWord(String word);
}

Finally, the JobIntentService sends the result via LocalBroadcastManager to the hosting Activity and the activity calls a public method on the Fragment.

This path works, but you can see that it is very long and I had to write lot of boilerplate code to implement it.

Recently I've got a hint on Reddit, that LiveData is better for such cases and I have been reading on it and already switched some of my fragments to using it.

So I am trying to switch this Fragment to using LiveData too, by changing the signature of the method to:

@Dao
public interface MyDao {
    @Query("SELECT 1 FROM dictionary WHERE word = :word")
    LiveData<Integer> findWord(String word);
}

and invoking it from my Fragment:

public class MyFragment extends Fragment {
    private static final Pattern PATTERN = Pattern.compile("([A-Z]{2,})");

    private LiveData<Integer> mLiveData;

    private EditText mInputText;
    private CheckedTextView mResultText;

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container,
                             Bundle savedInstanceState) {
        ...
        mInputText.addTextChangedListener(new TextWatcher() {
            ...
            @Override
            public void afterTextChanged(Editable s) {
                String word = mInputText.getText().toString().trim().toUpperCase();
                if (PATTERN.matcher(word).matches()) {
                    mLiveData = MyDatabase.getInstance(getContext()).myDao().findWord(word);
                } else {
                    mResultText.setChecked(false);
                }
            }
        });

        mLiveData.observe(this, found -> {
            if (found != null && found == 1) {
                mResultText.setChecked(true);
            } else {
                mResultText.setChecked(false);
            }
        });

        return view;
    }

And the above method of course fails with NPE because mLiveData is null.

But how can I initiate it, when the word parameter to findWord(word) is changing?

Upvotes: 0

Views: 161

Answers (1)

Alexander Farber
Alexander Farber

Reputation: 22958

I have followed pskink's hint (thank you!) and the following seems to work for me:

public class MyFragment extends Fragment {
    private static final Pattern PATTERN = Pattern.compile("([A-Z]{2,})");

    private MutableLiveData<String> mTrigger = new MutableLiveData<>();
    private LiveData<Integer> mResult = Transformations.switchMap(mTrigger, 
        word -> MyDatabase.getInstance(getContext()).myDao().findWord(word));

    private EditText mInputText;
    private CheckedTextView mResultText;

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container,
                             Bundle savedInstanceState) {
        ...
        mInputText.addTextChangedListener(new TextWatcher() {
            ...
            @Override
            public void afterTextChanged(Editable s) {
                String word = mInputText.getText().toString().trim().toUpperCase();
                if (PATTERN.matcher(word).matches()) {
                    mTrigger.setValue(word);
                } else {
                    mResultText.setChecked(false);
                }
            }
        });

        mLiveData.observe(this, found -> {
            if (found != null && found == 1) {
                mResultText.setChecked(true);
            } else {
                mResultText.setChecked(false);
            }
        });

        return view;
    }

Upvotes: 1

Related Questions