【问题标题】:How to use LiveData, when the DAO method requires a changing parameter?当 DAO 方法需要更改参数时,如何使用 LiveData?
【发布时间】:2019-04-07 13:16:54
【问题描述】:

在使用 Room 存储单词的字典应用中,我有一个带有 TextField 的片段。

当用户在 TextField 中输入一个单词时,我会提取文本并将其发送到 JobIntentService,然后它会在自己的线程上同步调用 DAO 方法:

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

最后,JobIntentService 通过 LocalBroadcastManager 将结果发送到宿主 Activity,该 Activity 调用 Fragment 上的公共方法。

这个路径可行,但是你可以看到它很长,我不得不写很多样板代码来实现它。

最近我在 Reddit 上得到了一个提示,LiveData 更适合这种情况,我一直在阅读它并且已经将 some of my fragments 切换到使用它。

所以我也尝试将此 Fragment 切换为使用 LiveData,方法是将方法的签名更改为:

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

并从我的 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;
    }

由于mLiveData为空,上述方法当然会因NPE而失败。

但是当findWord(word) 的word 参数发生变化时,我该如何启动它?

【问题讨论】:

  • 使用Transformations#switchMap

标签: android android-room observer-pattern android-architecture-components android-livedata


【解决方案1】:

我已按照 pskink 的提示(谢谢!),以下似乎对我有用:

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

【讨论】:

  • 这正是我的意思......现在你可以observe()你的mResult
  • 谢谢!但是,既然我已经直接从 Fragment 使用 LiveData,我想知道为什么我会想要使用自定义 ViewModel?有什么好处?
  • 嗯,例如方向变化?我的意思是从纵向旋转到横向...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-12
  • 2016-01-02
  • 1970-01-01
  • 1970-01-01
  • 2021-12-09
  • 2019-01-02
相关资源
最近更新 更多