随着数据库更改,我不断增加对我的可观察对象的重复 onChange 传递
i keep getting increased repetitive onChange passes on my observables with database changes
我有一个词典应用程序,我想在其中将现有的同义词分配给词典中的一个词。为此,我使用的是在单词和同义词 table 之间使用 M:N 关系。
实体:
@Entity(tableName = "word_table",
indices = @Index(value = "word", unique = true))
public class Word {
@PrimaryKey(autoGenerate = true)
private long id;
private String word;
@Ignore
public Word(String word) {
this.word = word;
}
public Word(long id, String word) {
this.id = id;
this.word = word;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
}
@Entity(tableName = "synonym_table")
public class Synonym {
@PrimaryKey(autoGenerate = true)
private long sid;
private String synonym;
@Ignore
public Synonym(String synonym) {
this.synonym = synonym;
}
public Synonym(long sid, String synonym) {
this.sid = sid;
this.synonym = synonym;
}
public long getSid() {
return sid;
}
public void setSid(long id) {
this.sid = sid;
}
public String getSynonym() {
return synonym;
}
public void setSynonym(String synonym) {
this.synonym = synonym;
}
}
@Entity(tableName = "word_synonym_join_table",
primaryKeys= {"word_id" , "synonym_id"},
foreignKeys = {@ForeignKey(entity = Word.class, parentColumns = "id", childColumns = "word_id"),
@ForeignKey(entity = Synonym.class, parentColumns = "sid", childColumns = "synonym_id")})
public class WordSynonymJoin {
@ColumnInfo(name = "word_id")
private long wordId;
@ColumnInfo(name = "synonym_id")
private long synonymId;
public WordSynonymJoin(long wordId, long synonymId) {
this.wordId = wordId;
this.synonymId = synonymId;
}
public long getWordId() {
return wordId;
}
public void setWordId(long wordId) {
this.wordId = wordId;
}
public long getSynonymId() {
return synonymId;
}
public void setSynonymId(long synonymId) {
this.synonymId = synonymId;
}
}
为了检索 Word 和相关同义词的数据,我创建了一个名为 WordWithSynonyms 的 POJO。
public class WordWithSynonyms {
@Embedded
public Word word;
@Embedded
public WordSynonymJoin wordSynonymJoin;
}
道如下:
@Dao
public interface WordDao {
@Query("SELECT * FROM word_table")
public LiveData<List<Word>> getAllWords();
@Query("SELECT * FROM word_table WHERE id =:wordId")
public LiveData<List<Word>> getWordById(long wordId);
@Query("SELECT * from word_table WHERE word =:value")
public LiveData<List<Word>> getWordByValue(String value);
@Insert
public long insert(Word word);
@Delete
public void delete(Word word);
@Update
public void update(Word word);
@Query("DELETE FROM word_table")
public void deleteAll();
}
@Dao
public interface SynonymDao {
@Query("SELECT * FROM synonym_table")
public LiveData<List<Synonym>> getAllSynonyms();
@Query("SELECT * FROM synonym_table WHERE synonym =:value")
public LiveData<List<Synonym>> getSynonymByValue(String value);
@Insert
public void insert(Synonym synonym);
@Delete
public void delete(Synonym synonym);
@Query("DELETE FROM synonym_table")
public void deleteAll();
}
@Dao
public interface WordSynonymJoinDao {
@Query("SELECT * FROM word_table INNER JOIN word_synonym_join_table " +
"ON word_table.id = word_synonym_join_table.word_id " +
"WHERE word_synonym_join_table.synonym_id =:synonymId")
public LiveData<List<WordWithSynonyms>> getWordsBySynonym(long synonymId);
@Query("SELECT * FROM synonym_table INNER JOIN word_synonym_join_table " +
"ON synonym_table.sid = word_synonym_join_table.synonym_id " +
"WHERE word_synonym_join_table.word_id =:wordId")
public LiveData<List<SynonymWithWords>> getSynonymsByWord(long wordId);
@Query("SELECT * FROM synonym_table INNER JOIN word_synonym_join_table " +
"ON synonym_table.sid = word_synonym_join_table.synonym_id " +
"WHERE word_synonym_join_table.word_id !=:wordId")
public LiveData<List<SynonymWithWords>> getSynonymsByNotWord(long wordId);
@Insert
public void insert(WordSynonymJoin wordSynonymJoin);
@Delete
public void delete(WordSynonymJoin wordSynonymJoin);
@Query("DELETE FROM word_synonym_join_table")
public void deleteAll();
}
当我到达同义词 Activity 时,我传递 wordId 以通过 ViewModel 观察器检索该词的当前同义词。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_synonym);
Intent intent = getIntent();
wordId = Long.parseLong(intent.getStringExtra(EXTRA_WORD_ID));
//SynonymViewModel synonymViewModel = ViewModelProviders.of(this).get(SynonymViewModel.class);
WordSynonymJoinViewModel wordSynonymJoinViewModel = ViewModelProviders.of(this).get(WordSynonymJoinViewModel.class);
//synonymAdapter = new SynonymListAdapter(this);
synonymAdapter = new SynonymWithWordListAdapter(this);
synonynRecyclerView = findViewById(R.id.recycler_view_syonym);
if (wordId != 0) {
wordSynonymJoinViewModel.getSynonymsByWord(wordId).observe(SynonymActivity.this, new Observer<List<SynonymWithWords>>() {
@Override
public void onChanged(@Nullable List<SynonymWithWords> synonymWithWords) {
synonymAdapter.setSynonyms(synonymWithWords);
synonymAdapter.notifyDataSetChanged();
}
});
}
synonynRecyclerView.setAdapter(synonymAdapter);
synonynRecyclerView.setLayoutManager(new LinearLayoutManager(SynonymActivity.this));
}
然后我给用户机会将同义词 table 中的一个现有的、未分配的同义词关联到单词 table。
我通过 AlertDialog 内的单独 ViewModel 观察器检索未使用和可用的同义词,AlertDialog 使用微调器通过 WordSynonymJoin table 使用另一个 ViewModel 观察器来显示它们。
最后,当用户单击 AlertDialog 上的“确定”按钮时,在该 ViewModel 观察器内部,第三个 VieModel 观察器 运行 实际插入到 WordSynonymJoin table.
case R.id.synonym_assign_synonym:
final WordSynonymJoinViewModel wordSynonymJoinViewModel = ViewModelProviders.of(SynonymActivity.this).get(WordSynonymJoinViewModel.class);
wordSynonymJoinViewModel.getSynonymsByNotWord(wordId).observe(SynonymActivity.this, new Observer<List<SynonymWithWords>>() {
@Override
public void onChanged(@Nullable List<SynonymWithWords> synonymWithWords) {
List<String> synonymsNotAssignList = new ArrayList<>();
for (SynonymWithWords sww : synonymWithWords)
synonymsNotAssignList.add(sww.synonym.getSynonym());
AlertDialog.Builder assignSynonymDialog = new AlertDialog.Builder(SynonymActivity.this);
assignSynonymDialog.setTitle("Select New Category:");
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.alert_dialog_spinner_view, null);
final Spinner synonymSpinner = (Spinner) view.findViewById(R.id.alert_dialog_spinner);
final SynonymViewModel synonymViewModel = ViewModelProviders.of(SynonymActivity.this).get(SynonymViewModel.class);
ArrayAdapter<String> spinnerAdapter = new ArrayAdapter(SynonymActivity.this, android.R.layout.simple_spinner_dropdown_item, synonymsNotAssignList);
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
synonymSpinner.setAdapter(spinnerAdapter);
synonymSpinner.setSelection(synonymId);
assignSynonymDialog.setView(view);
assignSynonymDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
final String synonymValue = synonymSpinner.getSelectedItem().toString();
// get new synonym id
synonymViewModel.getSynonymByValue(synonymValue).observe(SynonymActivity.this, new Observer<List<Synonym>>() {
@Override
public void onChanged(@Nullable List<Synonym> synonyms) {
long id = 0;
if (!synonyms.get(0).getSynonym().equals(synonymValue)) {
if (synonyms.size() > 1)
Toast.makeText(SynonymActivity.this, "Query found " + synonyms.size() + " which is more than the one expected.", Toast.LENGTH_SHORT).show();
} else {
id = synonyms.get(0).getSid();
}
WordSynonymJoinViewModel wordSynonymJoinViewModel = ViewModelProviders.of(SynonymActivity.this).get(WordSynonymJoinViewModel.class);
wordSynonymJoinViewModel.insert(new WordSynonymJoin(wordId, id));
}
});
}
});
assignSynonymDialog.setNegativeButton("Cancel", null);
assignSynonymDialog.create();
assignSynonymDialog.show();
}
});
return true;
第一遍似乎一切正常。但是,在用户继续向单词添加新同义词的连续传递中,在添加每个同义词后需要多次单击 AlertDialog 的取消按钮才能退出。添加了 2 个同义词,2 单击取消返回主界面 Activity。添加了 3 个同义词,3 次单击取消以删除 AlertDialog。
我对 MVVM 和 Room 持久性的整个概念非常陌生,所以我知道会有问题。下面是 AlertDialog 的代码,用于将现有的、未分配的同义词添加到当前单词。
我不喜欢为此使用了多少代码,但我无法用词来表达我的搜索,因此我无法找到解决方法。
我的问题是:
为什么每次输入 associate new synonym to the word 时,代码都会循环 +1?我应该是在清理什么东西吧。
这个编码是否正确?
要完成看似很小的事情,这似乎是一项艰巨的工作。我想我错过了什么。我把它弄得异常复杂了吗?
这段代码看起来如此繁琐笨拙,我错过了什么?
这似乎是一种检索值的非常麻烦的方法,而且我真的不认为我需要观察上面 运行 的每个查询。也许我错了。
是否有可以帮助我更好地理解这一点的学习方向?
这会是 Rx Java 进来的地方吗?
我当然可以根据需要提供更多代码。
如有任何帮助,我们将不胜感激。
此处:
wordSynonymJoinViewModel.getSynonymsByNotWord(wordId).observe(SynonymActivity.this, new Observer<List<SynonymWithWords>>() {
您正在监视同义词,但在观察的内部,您会显示一个对话框并允许添加更多同义词。每次添加新的同义词时,它都会创建一个新的 AlertDialog。
所以这就是为什么您必须在每个对话框中按取消键的原因。
要解决这个问题,您可以将 AlertDialog 分配给一个字段并使用 isShowing()
方法来决定是否要显示另一个对话框(即,如果一个对话框已经显示,则不显示另一个。
https://developer.android.com/reference/android/app/Dialog.html#isShowing()
至于您的所有其他问题,很抱歉,我无法展开包装。
不过,我可以分享我的想法:
I want to assign existing synonyms to a word in the dictionary.
也许忘记了数据库开始并创建一个内存解决方案。
稍后您可以将其更改为持久化。
在内存中,该结构看起来像字典单词和同义词查找的哈希表 Map<String, List<String>>
。
这个地图将在一个名为 Repository
的 class 中,它以某种方式公开供您观察和更新它(RxJava Observable)或像您已经拥有的 LiveData。
你的 Fragment 会观察这个 Map,使用你想要的 MVVM 或 MVP 在 RecyclerView 中显示它。
你在 RecyclerView 的每一行上都有一个点击监听器来添加一个新的同义词。单击打开对话框(或新的 activity/fragment)。在用户键入同义词后,您将通过存储库将其保存到您的地图 - 因此原始观察者将更新 RecyclerView。
你不应该进入打开多个对话框的循环状态:/
希望对您有所帮助,说实话,听起来您的方向是对的,只需要再努力一点。
TRDL:不要在 ON_CREATE 状态之外调用 .observe
。
您犯了 LiveData
错误...但您并不孤单!这个错误是 Whosebug 上最常见的 LiveData
错误:在 Activity#onCreate()
之外调用 .observe
。这包括在点击侦听器、onResume
、广播接收器等中调用 .observe
。
我在大多数第一次使用 LivedData
的人身上看到的问题是,他们将 LiveData
视为回电,而实际上并非如此。 LiveData
是一个流。 LiveData
不止一次通知。附加到 LiveData
的 Observers
将继续收到通知,直到他们取消订阅。此外,它意味着在生命周期开始时订阅(例如 Activity#onCreate 或 Fragment#onViewCreated)并在生命周期结束时取消订阅。 LiveData
自动处理取消订阅部分,因此您只需确保在 onCreate
.
订阅即可
你不断获得 +1 对话的根本原因是之前的观察者没有死,并且你每次重复同样的事情时都会不断地向数据库添加新的订阅。尝试旋转 phone 并查看对话框的数量是否重置回 1。那是因为当您旋转屏幕并重新创建 activity 时,所有先前的观察者都已取消订阅。
也许您可以调用 isShowing()
并查看是否有打开的对话框,如另一个答案中所建议的那样。但是,这样做只是一种解决方法。如果它是 Toast
或其他您无法检查的内容怎么办?此外,您很幸运能够轻松发现此错误。您可能在其他地方没有看到这个重复的观察者错误。
所以我认为你已经知道如何使用LiveData
,但你只需要知道如何正确地实现反应模式。用一篇文章来解释太多了,但让我举一个简单的例子:
假设您有一个按钮,当您按下该按钮时,您会从数据库中获取一些数据。在类似回调的设计中,您经常调用 ViewModel 中的某些函数并传递回调实例。例如你有这个:
//ViewModel
void getSynonymsByNotWord(WordSynonymJoin word, Callback callback) { ... }
//Activity
void onClick(View v) {
wordSynonymJoinViewModel.changeCurrentSysnonymsByNotWord(wordId, callback);
}
您对 ViewModel 执行操作并通过回调接收响应。这非常适合回调。但是,您不能对 LiveData
执行相同的操作。当使用 LiveData
时,视图层不期望每个操作都会有响应。相反,View 层应该始终盲目地听取响应,甚至在单击按钮之前。
//ViewModel
private MutableLiveData wordQuery;
private Livedata synonymsByNotWord = Transformations.switchMap(wordQuery, word -> {
return repository.getSynonymsByWord(word);
});
LiveData getCurrentSynonymsByNotWord() {
return synonymsByNotWord;
}
void changeCurrentSynonymsByNotWord(WordSynonymJoin word) {
wordQuery.postValue(word);
}
//Activity
void onCreate() {
wordSynonymJoinViewModel.getCurrentSynonymsByNotWord().observe(...);
}
void onClick(View v) {
wordSynonymJoinViewModel.changeCurrentSynonymsByNotWord(wordId);
}
也可以,但是您通常不会在每次需要视图模型时都从 ViewModelProviders
获取 ViewModel。您应该只在 onCreate
处获取一个视图模型,将其保存为 activity 实例变量,并在 activity.
的其余部分使用相同的实例
我有一个词典应用程序,我想在其中将现有的同义词分配给词典中的一个词。为此,我使用的是在单词和同义词 table 之间使用 M:N 关系。
实体:
@Entity(tableName = "word_table",
indices = @Index(value = "word", unique = true))
public class Word {
@PrimaryKey(autoGenerate = true)
private long id;
private String word;
@Ignore
public Word(String word) {
this.word = word;
}
public Word(long id, String word) {
this.id = id;
this.word = word;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
}
@Entity(tableName = "synonym_table")
public class Synonym {
@PrimaryKey(autoGenerate = true)
private long sid;
private String synonym;
@Ignore
public Synonym(String synonym) {
this.synonym = synonym;
}
public Synonym(long sid, String synonym) {
this.sid = sid;
this.synonym = synonym;
}
public long getSid() {
return sid;
}
public void setSid(long id) {
this.sid = sid;
}
public String getSynonym() {
return synonym;
}
public void setSynonym(String synonym) {
this.synonym = synonym;
}
}
@Entity(tableName = "word_synonym_join_table",
primaryKeys= {"word_id" , "synonym_id"},
foreignKeys = {@ForeignKey(entity = Word.class, parentColumns = "id", childColumns = "word_id"),
@ForeignKey(entity = Synonym.class, parentColumns = "sid", childColumns = "synonym_id")})
public class WordSynonymJoin {
@ColumnInfo(name = "word_id")
private long wordId;
@ColumnInfo(name = "synonym_id")
private long synonymId;
public WordSynonymJoin(long wordId, long synonymId) {
this.wordId = wordId;
this.synonymId = synonymId;
}
public long getWordId() {
return wordId;
}
public void setWordId(long wordId) {
this.wordId = wordId;
}
public long getSynonymId() {
return synonymId;
}
public void setSynonymId(long synonymId) {
this.synonymId = synonymId;
}
}
为了检索 Word 和相关同义词的数据,我创建了一个名为 WordWithSynonyms 的 POJO。
public class WordWithSynonyms {
@Embedded
public Word word;
@Embedded
public WordSynonymJoin wordSynonymJoin;
}
道如下:
@Dao
public interface WordDao {
@Query("SELECT * FROM word_table")
public LiveData<List<Word>> getAllWords();
@Query("SELECT * FROM word_table WHERE id =:wordId")
public LiveData<List<Word>> getWordById(long wordId);
@Query("SELECT * from word_table WHERE word =:value")
public LiveData<List<Word>> getWordByValue(String value);
@Insert
public long insert(Word word);
@Delete
public void delete(Word word);
@Update
public void update(Word word);
@Query("DELETE FROM word_table")
public void deleteAll();
}
@Dao
public interface SynonymDao {
@Query("SELECT * FROM synonym_table")
public LiveData<List<Synonym>> getAllSynonyms();
@Query("SELECT * FROM synonym_table WHERE synonym =:value")
public LiveData<List<Synonym>> getSynonymByValue(String value);
@Insert
public void insert(Synonym synonym);
@Delete
public void delete(Synonym synonym);
@Query("DELETE FROM synonym_table")
public void deleteAll();
}
@Dao
public interface WordSynonymJoinDao {
@Query("SELECT * FROM word_table INNER JOIN word_synonym_join_table " +
"ON word_table.id = word_synonym_join_table.word_id " +
"WHERE word_synonym_join_table.synonym_id =:synonymId")
public LiveData<List<WordWithSynonyms>> getWordsBySynonym(long synonymId);
@Query("SELECT * FROM synonym_table INNER JOIN word_synonym_join_table " +
"ON synonym_table.sid = word_synonym_join_table.synonym_id " +
"WHERE word_synonym_join_table.word_id =:wordId")
public LiveData<List<SynonymWithWords>> getSynonymsByWord(long wordId);
@Query("SELECT * FROM synonym_table INNER JOIN word_synonym_join_table " +
"ON synonym_table.sid = word_synonym_join_table.synonym_id " +
"WHERE word_synonym_join_table.word_id !=:wordId")
public LiveData<List<SynonymWithWords>> getSynonymsByNotWord(long wordId);
@Insert
public void insert(WordSynonymJoin wordSynonymJoin);
@Delete
public void delete(WordSynonymJoin wordSynonymJoin);
@Query("DELETE FROM word_synonym_join_table")
public void deleteAll();
}
当我到达同义词 Activity 时,我传递 wordId 以通过 ViewModel 观察器检索该词的当前同义词。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_synonym);
Intent intent = getIntent();
wordId = Long.parseLong(intent.getStringExtra(EXTRA_WORD_ID));
//SynonymViewModel synonymViewModel = ViewModelProviders.of(this).get(SynonymViewModel.class);
WordSynonymJoinViewModel wordSynonymJoinViewModel = ViewModelProviders.of(this).get(WordSynonymJoinViewModel.class);
//synonymAdapter = new SynonymListAdapter(this);
synonymAdapter = new SynonymWithWordListAdapter(this);
synonynRecyclerView = findViewById(R.id.recycler_view_syonym);
if (wordId != 0) {
wordSynonymJoinViewModel.getSynonymsByWord(wordId).observe(SynonymActivity.this, new Observer<List<SynonymWithWords>>() {
@Override
public void onChanged(@Nullable List<SynonymWithWords> synonymWithWords) {
synonymAdapter.setSynonyms(synonymWithWords);
synonymAdapter.notifyDataSetChanged();
}
});
}
synonynRecyclerView.setAdapter(synonymAdapter);
synonynRecyclerView.setLayoutManager(new LinearLayoutManager(SynonymActivity.this));
}
然后我给用户机会将同义词 table 中的一个现有的、未分配的同义词关联到单词 table。
我通过 AlertDialog 内的单独 ViewModel 观察器检索未使用和可用的同义词,AlertDialog 使用微调器通过 WordSynonymJoin table 使用另一个 ViewModel 观察器来显示它们。 最后,当用户单击 AlertDialog 上的“确定”按钮时,在该 ViewModel 观察器内部,第三个 VieModel 观察器 运行 实际插入到 WordSynonymJoin table.
case R.id.synonym_assign_synonym:
final WordSynonymJoinViewModel wordSynonymJoinViewModel = ViewModelProviders.of(SynonymActivity.this).get(WordSynonymJoinViewModel.class);
wordSynonymJoinViewModel.getSynonymsByNotWord(wordId).observe(SynonymActivity.this, new Observer<List<SynonymWithWords>>() {
@Override
public void onChanged(@Nullable List<SynonymWithWords> synonymWithWords) {
List<String> synonymsNotAssignList = new ArrayList<>();
for (SynonymWithWords sww : synonymWithWords)
synonymsNotAssignList.add(sww.synonym.getSynonym());
AlertDialog.Builder assignSynonymDialog = new AlertDialog.Builder(SynonymActivity.this);
assignSynonymDialog.setTitle("Select New Category:");
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.alert_dialog_spinner_view, null);
final Spinner synonymSpinner = (Spinner) view.findViewById(R.id.alert_dialog_spinner);
final SynonymViewModel synonymViewModel = ViewModelProviders.of(SynonymActivity.this).get(SynonymViewModel.class);
ArrayAdapter<String> spinnerAdapter = new ArrayAdapter(SynonymActivity.this, android.R.layout.simple_spinner_dropdown_item, synonymsNotAssignList);
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
synonymSpinner.setAdapter(spinnerAdapter);
synonymSpinner.setSelection(synonymId);
assignSynonymDialog.setView(view);
assignSynonymDialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
final String synonymValue = synonymSpinner.getSelectedItem().toString();
// get new synonym id
synonymViewModel.getSynonymByValue(synonymValue).observe(SynonymActivity.this, new Observer<List<Synonym>>() {
@Override
public void onChanged(@Nullable List<Synonym> synonyms) {
long id = 0;
if (!synonyms.get(0).getSynonym().equals(synonymValue)) {
if (synonyms.size() > 1)
Toast.makeText(SynonymActivity.this, "Query found " + synonyms.size() + " which is more than the one expected.", Toast.LENGTH_SHORT).show();
} else {
id = synonyms.get(0).getSid();
}
WordSynonymJoinViewModel wordSynonymJoinViewModel = ViewModelProviders.of(SynonymActivity.this).get(WordSynonymJoinViewModel.class);
wordSynonymJoinViewModel.insert(new WordSynonymJoin(wordId, id));
}
});
}
});
assignSynonymDialog.setNegativeButton("Cancel", null);
assignSynonymDialog.create();
assignSynonymDialog.show();
}
});
return true;
第一遍似乎一切正常。但是,在用户继续向单词添加新同义词的连续传递中,在添加每个同义词后需要多次单击 AlertDialog 的取消按钮才能退出。添加了 2 个同义词,2 单击取消返回主界面 Activity。添加了 3 个同义词,3 次单击取消以删除 AlertDialog。
我对 MVVM 和 Room 持久性的整个概念非常陌生,所以我知道会有问题。下面是 AlertDialog 的代码,用于将现有的、未分配的同义词添加到当前单词。
我不喜欢为此使用了多少代码,但我无法用词来表达我的搜索,因此我无法找到解决方法。
我的问题是:
为什么每次输入 associate new synonym to the word 时,代码都会循环 +1?我应该是在清理什么东西吧。
这个编码是否正确?
要完成看似很小的事情,这似乎是一项艰巨的工作。我想我错过了什么。我把它弄得异常复杂了吗?
这段代码看起来如此繁琐笨拙,我错过了什么?
这似乎是一种检索值的非常麻烦的方法,而且我真的不认为我需要观察上面 运行 的每个查询。也许我错了。
是否有可以帮助我更好地理解这一点的学习方向?
这会是 Rx Java 进来的地方吗?
我当然可以根据需要提供更多代码。
如有任何帮助,我们将不胜感激。
此处:
wordSynonymJoinViewModel.getSynonymsByNotWord(wordId).observe(SynonymActivity.this, new Observer<List<SynonymWithWords>>() {
您正在监视同义词,但在观察的内部,您会显示一个对话框并允许添加更多同义词。每次添加新的同义词时,它都会创建一个新的 AlertDialog。
所以这就是为什么您必须在每个对话框中按取消键的原因。
要解决这个问题,您可以将 AlertDialog 分配给一个字段并使用 isShowing()
方法来决定是否要显示另一个对话框(即,如果一个对话框已经显示,则不显示另一个。
https://developer.android.com/reference/android/app/Dialog.html#isShowing()
至于您的所有其他问题,很抱歉,我无法展开包装。
不过,我可以分享我的想法:
I want to assign existing synonyms to a word in the dictionary.
也许忘记了数据库开始并创建一个内存解决方案。 稍后您可以将其更改为持久化。
在内存中,该结构看起来像字典单词和同义词查找的哈希表 Map<String, List<String>>
。
这个地图将在一个名为 Repository
的 class 中,它以某种方式公开供您观察和更新它(RxJava Observable)或像您已经拥有的 LiveData。
你的 Fragment 会观察这个 Map,使用你想要的 MVVM 或 MVP 在 RecyclerView 中显示它。
你在 RecyclerView 的每一行上都有一个点击监听器来添加一个新的同义词。单击打开对话框(或新的 activity/fragment)。在用户键入同义词后,您将通过存储库将其保存到您的地图 - 因此原始观察者将更新 RecyclerView。
你不应该进入打开多个对话框的循环状态:/
希望对您有所帮助,说实话,听起来您的方向是对的,只需要再努力一点。
TRDL:不要在 ON_CREATE 状态之外调用 .observe
。
您犯了 LiveData
错误...但您并不孤单!这个错误是 Whosebug 上最常见的 LiveData
错误:在 Activity#onCreate()
之外调用 .observe
。这包括在点击侦听器、onResume
、广播接收器等中调用 .observe
。
我在大多数第一次使用 LivedData
的人身上看到的问题是,他们将 LiveData
视为回电,而实际上并非如此。 LiveData
是一个流。 LiveData
不止一次通知。附加到 LiveData
的 Observers
将继续收到通知,直到他们取消订阅。此外,它意味着在生命周期开始时订阅(例如 Activity#onCreate 或 Fragment#onViewCreated)并在生命周期结束时取消订阅。 LiveData
自动处理取消订阅部分,因此您只需确保在 onCreate
.
你不断获得 +1 对话的根本原因是之前的观察者没有死,并且你每次重复同样的事情时都会不断地向数据库添加新的订阅。尝试旋转 phone 并查看对话框的数量是否重置回 1。那是因为当您旋转屏幕并重新创建 activity 时,所有先前的观察者都已取消订阅。
也许您可以调用 isShowing()
并查看是否有打开的对话框,如另一个答案中所建议的那样。但是,这样做只是一种解决方法。如果它是 Toast
或其他您无法检查的内容怎么办?此外,您很幸运能够轻松发现此错误。您可能在其他地方没有看到这个重复的观察者错误。
所以我认为你已经知道如何使用LiveData
,但你只需要知道如何正确地实现反应模式。用一篇文章来解释太多了,但让我举一个简单的例子:
假设您有一个按钮,当您按下该按钮时,您会从数据库中获取一些数据。在类似回调的设计中,您经常调用 ViewModel 中的某些函数并传递回调实例。例如你有这个:
//ViewModel
void getSynonymsByNotWord(WordSynonymJoin word, Callback callback) { ... }
//Activity
void onClick(View v) {
wordSynonymJoinViewModel.changeCurrentSysnonymsByNotWord(wordId, callback);
}
您对 ViewModel 执行操作并通过回调接收响应。这非常适合回调。但是,您不能对 LiveData
执行相同的操作。当使用 LiveData
时,视图层不期望每个操作都会有响应。相反,View 层应该始终盲目地听取响应,甚至在单击按钮之前。
//ViewModel
private MutableLiveData wordQuery;
private Livedata synonymsByNotWord = Transformations.switchMap(wordQuery, word -> {
return repository.getSynonymsByWord(word);
});
LiveData getCurrentSynonymsByNotWord() {
return synonymsByNotWord;
}
void changeCurrentSynonymsByNotWord(WordSynonymJoin word) {
wordQuery.postValue(word);
}
//Activity
void onCreate() {
wordSynonymJoinViewModel.getCurrentSynonymsByNotWord().observe(...);
}
void onClick(View v) {
wordSynonymJoinViewModel.changeCurrentSynonymsByNotWord(wordId);
}
也可以,但是您通常不会在每次需要视图模型时都从 ViewModelProviders
获取 ViewModel。您应该只在 onCreate
处获取一个视图模型,将其保存为 activity 实例变量,并在 activity.