当 DAO 方法需要更改参数时,如何使用 LiveData?
How to use LiveData, when the DAO method requires a changing parameter?
在使用 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 上的 public 方法。
这个路径可行,但是你可以看到它很长,我不得不写很多样板代码来实现它。
最近我在 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)
的单词参数发生变化时,我该如何启动它呢?
我遵循了 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;
}
在使用 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 上的 public 方法。
这个路径可行,但是你可以看到它很长,我不得不写很多样板代码来实现它。
最近我在 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)
的单词参数发生变化时,我该如何启动它呢?
我遵循了 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;
}