Как использовать LiveData, когда метод DAO требует изменения параметра? - PullRequest
0 голосов
/ 03 ноября 2018

В приложении-словаре, использующем Room для хранения слов, у меня есть фрагмент с TextField.

Когда пользователь вводит слово в TextField, я извлекаю текст и отправляю его в JobIntentService, который затем синхронно вызывает метод DAO в своем собственном потоке:

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

Наконец, JobIntentService отправляет результат через LocalBroadcastManager в активность хостинга, и операция вызывает открытый метод для фрагмента.

Этот путь работает, но вы можете видеть, что он очень длинный, и мне пришлось написать много шаблонного кода для его реализации.

Недавно я получил подсказку от Reddit, что LiveData лучше подходит для таких случаев, и я читал об этом и уже переключил некоторые из моих фрагментов на его использование.

Поэтому я пытаюсь переключить этот фрагмент на использование LiveData, изменив сигнатуру метода на:

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

и вызов его из моего фрагмента:

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;
    }

И приведенный выше метод, конечно, не работает с NPE, потому что mLiveData равен нулю.

Но как я могу его инициировать, когда параметр слова в findWord(word) меняется?

1 Ответ

0 голосов
/ 03 ноября 2018

Я следовал подсказке Пскинка (спасибо!), И мне кажется, что мне подходит следующее:

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;
    }
...