如何将普通数据(从房间返回)转换为 ViewModel 层上的 LiveData
How to convert normal data(returned from room) to LiveData on ViewModel layer
我正在使用带有 MVVM 模式的干净架构,因此房间部分进入数据层,我将可观察对象从那里返回到域层,并通过将它们包装在 LiveData 中来在表示层中使用它们。
现在,问题是在 insertion/deletion/update 之后,列表不会在 UI.
中立即更新
表示层中的视图模型:
public class WordViewModel extends BaseViewModel<WordNavigator> {
//get all the use cases here
private GetAllWords getAllWords;
private InsertWord insertWord;
private DeleteThisWord deleteThisWord;
private UpdateThisWord updateThisWord;
private GetTheIndexOfTopWord getTheIndexOfTopWord;
//data
public MutableLiveData<List<Word>> allWords;
public WordViewModel(GetAllWords getAllWords, InsertWord insertWord, DeleteThisWord deleteThisWord, UpdateThisWord updateThisWord, GetTheIndexOfTopWord getTheIndexOfTopWord) {
this.getAllWords = getAllWords;
this.insertWord = insertWord;
this.deleteThisWord = deleteThisWord;
this.updateThisWord = updateThisWord;
this.getTheIndexOfTopWord = getTheIndexOfTopWord;
}
public void getAllWords() {
getAllWords.execute(new DisposableObserver<List<Word>>() {
@Override
public void onNext(List<Word> words) {
allWords.setValue(words);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
}, GetAllWords.Params.getAllWords());
}
public void insertWord(Word word) {
insertWord.execute(new DisposableObserver<Boolean>() {
@Override
public void onNext(Boolean aBoolean) {
if (aBoolean)
Log.e("ganesh", "word inserted successfully!!!");
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
}
}, InsertWord.Params.insertWord(word));
}
public void getTheIndexOfTopWord(final String action) {
getTheIndexOfTopWord.execute(new DisposableObserver<Word>() {
@Override
public void onNext(Word word) {
if (word != null)
getNavigator().updateTopIndex(word.getWordId(), action);
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
}
}, GetTheIndexOfTopWord.Params.getTheIndexOfTopWord());
}
public void deleteThisWord(int wordId) {
deleteThisWord.execute(new DisposableObserver<Boolean>() {
@Override
public void onNext(Boolean aBoolean) {
if (aBoolean)
Log.e("ganesh", "word deleted successfully!!!");
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
}
}, DeleteThisWord.Params.deleteThisWord(wordId));
}
public void updateThisWord(int wordId, String newWord) {
updateThisWord.execute(new DisposableObserver<Boolean>() {
@Override
public void onNext(Boolean aBoolean) {
if (aBoolean)
Log.e("ganesh", "word updated successfully!!!");
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
}
}, UpdateThisWord.Params.updateThisWord(wordId, newWord));
}
public MutableLiveData<List<Word>> getWords() {
if (allWords == null) {
allWords = new MutableLiveData<>();
}
return allWords;
}
@Override
protected void onCleared() {
super.onCleared();
if (getAllWords != null)
getAllWords = null;
if (deleteThisWord != null)
deleteThisWord = null;
if (insertWord != null)
insertWord = null;
if (updateThisWord != null)
updateThisWord = null;
if (getTheIndexOfTopWord != null)
getTheIndexOfTopWord = null;
}
}
数据层中的 DAO:
@Dao
public interface WordDao {
@Insert
void insertThisWord(Word word);
@Query("delete from word_table")
void deleteAll();
@Query("select * from word_table order by word_id asc")
List<Word> getAllWords();
@Query("delete from word_table where word_id = :wordId")
void deleteThisWord(int wordId);
@Query("update word_table set word = :newWord where word_id = :wordId")
void updateThisWord(int wordId, String newWord);
@Query("select * from word_table order by word_id asc limit 1")
Word getTheIndexOfTopWord();
}
数据层中的存储库:
public class WordRepositoryImpl implements WordRepository {
private ApiInterface apiInterface;
private SharedPreferenceHelper sharedPreferenceHelper;
private Context context;
private WordDao wordDao;
private WordRoomDatabase db;
public WordRepositoryImpl(ApiInterface apiInterface, SharedPreferenceHelper sharedPreferenceHelper, WordRoomDatabase db, Context context) {
this.apiInterface = apiInterface;
this.sharedPreferenceHelper = sharedPreferenceHelper;
this.context = context;
this.db = db;
wordDao = db.wordDao();
}
@Override
public Observable<Integer> sum(final int a, final int b) {
return Observable.fromCallable(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return (a + b);
}
});
}
@Override
public Observable<List<Word>> getAllWords() {
return Observable.fromCallable(new Callable<List<Word>>() {
@Override
public List<Word> call() throws Exception {
List<Word> list = new ArrayList<>();
List<com.example.data.models.Word> listWords = db.wordDao().getAllWords();
for (com.example.data.models.Word item : listWords) {
list.add(new Word(item.getWordId(), item.getWord(), item.getWordLength()));
}
return list;
}
});
}
@Override
public Observable<Boolean> insertThisWord(final Word word) {
return Observable.fromCallable(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
com.example.data.models.Word item = new com.example.data.models.Word(word.getWord(), word.getWordLength());
db.wordDao().insertThisWord(item);
return true;
}
});
}
@Override
public Observable<Boolean> deleteThisWord(final int wordId) {
return Observable.fromCallable(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
db.wordDao().deleteThisWord(wordId);
return true;
}
});
}
@Override
public Observable<Boolean> updateThisWord(final int wordId, final String newWord) {
return Observable.fromCallable(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
db.wordDao().updateThisWord(wordId, newWord);
return true;
}
});
}
@Override
public Observable<Word> getTheIndexOfTopWord() {
return Observable.fromCallable(new Callable<Word>() {
@Override
public Word call() throws Exception {
com.example.data.models.Word item = db.wordDao().getTheIndexOfTopWord();
Word word = new Word(item.getWordId(), item.getWord(), item.getWordLength());
return word;
}
});
}
}
领域层中的 GetAllWordsUseCase:
public class GetAllWords extends UseCase<List<Word>, GetAllWords.Params> {
private WordRepository wordRepository;
public GetAllWords(PostExecutionThread postExecutionThread, WordRepository wordRepository) {
super(postExecutionThread);
this.wordRepository = wordRepository;
}
@Override
public Observable<List<Word>> buildUseCaseObservable(Params params) {
return wordRepository.getAllWords();
}
public static final class Params {
private Params() {
}
public static GetAllWords.Params getAllWords() {
return new GetAllWords.Params();
}
}
}
领域层中的用例库Class:
public abstract class UseCase<T, Params> {
private final PostExecutionThread postExecutionThread;
private final CompositeDisposable compositeDisposable;
public UseCase(PostExecutionThread postExecutionThread) {
this.postExecutionThread = postExecutionThread;
this.compositeDisposable = new CompositeDisposable();
}
/**
* Builds an {@link Observable} which will be used when executing the current {@link UseCase}.
*/
public abstract Observable<T> buildUseCaseObservable(Params params);
/**
* Dispose from current {@link CompositeDisposable}.
*/
public void dispose() {
if (!compositeDisposable.isDisposed()) {
compositeDisposable.dispose();
}
}
/**
* Executes the current use case.
*
* @param observer {@link DisposableObserver} which will be listening to the observable build
* by {@link #buildUseCaseObservable(Params)} ()} method.
* @param params Parameters (Optional) used to build/execute this use case.
*/
public void execute(DisposableObserver<T> observer, Params params) {
if (observer != null) {
final Observable<T> observable = this.buildUseCaseObservable(params)
.subscribeOn(Schedulers.io())
.observeOn(postExecutionThread.getScheduler());
addDisposable(observable.subscribeWith(observer));
}
}
/**
* Dispose from current {@link CompositeDisposable}.
*/
private void addDisposable(Disposable disposable) {
if (disposable != null && compositeDisposable != null)
compositeDisposable.add(disposable);
}
}
最后,表示层中的WordActivity
public class WordActivity extends BaseActivity<WordViewModel> implements
View.OnClickListener, WordNavigator {
@Inject
WordViewModel wordViewModel;
private Button deleteButton, updateButton, addButton;
private EditText editTextWord;
private WordListAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_word);
((MainApplication) getApplicationContext()).getComponent().inject(this);
editTextWord = findViewById(R.id.activity_word_et_word);
deleteButton = findViewById(R.id.activity_main_delete_button);
updateButton = findViewById(R.id.activity_main_update_button);
addButton = findViewById(R.id.activity_word_btn_add_word);
deleteButton.setOnClickListener(this);
updateButton.setOnClickListener(this);
addButton.setOnClickListener(this);
RecyclerView recyclerView = findViewById(R.id.recyclerview);
adapter = new WordListAdapter(this);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
getViewModel().setNavigator(this);
getViewModel().getAllWords();
getViewModel().getWords().observe(this, new Observer<List<Word>>() {
@Override
public void onChanged(@android.support.annotation.Nullable List<Word> words) {
adapter.setWords(words);
}
});
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.activity_main_delete_button:
getViewModel().getTheIndexOfTopWord(TOP_INDEX_ACTION_DELETE);
break;
case R.id.activity_main_update_button:
getViewModel().getTheIndexOfTopWord(TOP_INDEX_ACTION_UPDATE);
break;
case R.id.activity_word_btn_add_word:
handleAddButtonClick();
break;
}
}
public void handleAddButtonClick() {
String text = editTextWord.getText().toString();
if (text.equals("")) {
Toast.makeText(getApplicationContext(), R.string.empty_not_saved, Toast.LENGTH_LONG).show();
} else {
Word word = new Word(text, text.length());
getViewModel().insertWord(word);
editTextWord.setText("");
editTextWord.clearFocus();
}
}
@Override
public void updateTopIndex(Integer wordId, String action) {
if (action.equals(TOP_INDEX_ACTION_DELETE))
getViewModel().deleteThisWord(wordId);
else
getViewModel().updateThisWord(wordId, "dsakagdad");
}
@Override
public WordViewModel getViewModel() {
return wordViewModel;
}
}
**getViewModel().getWords().observe(this, new Observer<List<Word>>() {
@Override
public void onChanged(@android.support.annotation.Nullable List<Word> words) {
adapter.setWords(words);
}
});**
//This portion is getting called only once but not when I
insert/update/delete words from room database!
任何人都可以通过这些并帮助我在这里!
DAO 中的这个方法将查询列表,return 它就像一个普通的 SQL 查询:
@Query("select * from word_table order by word_id asc")
List<Word> getAllWords();
如果您想观察变化,您可能需要考虑使用 RxJava2 Flowable/Observable
或 LiveData
。
因为我更喜欢 RxJava 方法,它看起来像这样:
@Query("select * from word_table order by word_id asc")
Flowable<List<Word>> getAllWords();
// or
Observable<List<Word>> getAllWords();
完成后,您可能想将存储库中的 getAllWords
方法更改为 return 即 Flowable/Observable
.
注意:使用 Observable
或 Flowable
两者都会最初发出一次查询结果,然后开始观察进一步的变化,直到取消订阅。
我正在使用带有 MVVM 模式的干净架构,因此房间部分进入数据层,我将可观察对象从那里返回到域层,并通过将它们包装在 LiveData 中来在表示层中使用它们。 现在,问题是在 insertion/deletion/update 之后,列表不会在 UI.
中立即更新表示层中的视图模型:
public class WordViewModel extends BaseViewModel<WordNavigator> {
//get all the use cases here
private GetAllWords getAllWords;
private InsertWord insertWord;
private DeleteThisWord deleteThisWord;
private UpdateThisWord updateThisWord;
private GetTheIndexOfTopWord getTheIndexOfTopWord;
//data
public MutableLiveData<List<Word>> allWords;
public WordViewModel(GetAllWords getAllWords, InsertWord insertWord, DeleteThisWord deleteThisWord, UpdateThisWord updateThisWord, GetTheIndexOfTopWord getTheIndexOfTopWord) {
this.getAllWords = getAllWords;
this.insertWord = insertWord;
this.deleteThisWord = deleteThisWord;
this.updateThisWord = updateThisWord;
this.getTheIndexOfTopWord = getTheIndexOfTopWord;
}
public void getAllWords() {
getAllWords.execute(new DisposableObserver<List<Word>>() {
@Override
public void onNext(List<Word> words) {
allWords.setValue(words);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
}, GetAllWords.Params.getAllWords());
}
public void insertWord(Word word) {
insertWord.execute(new DisposableObserver<Boolean>() {
@Override
public void onNext(Boolean aBoolean) {
if (aBoolean)
Log.e("ganesh", "word inserted successfully!!!");
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
}
}, InsertWord.Params.insertWord(word));
}
public void getTheIndexOfTopWord(final String action) {
getTheIndexOfTopWord.execute(new DisposableObserver<Word>() {
@Override
public void onNext(Word word) {
if (word != null)
getNavigator().updateTopIndex(word.getWordId(), action);
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
}
}, GetTheIndexOfTopWord.Params.getTheIndexOfTopWord());
}
public void deleteThisWord(int wordId) {
deleteThisWord.execute(new DisposableObserver<Boolean>() {
@Override
public void onNext(Boolean aBoolean) {
if (aBoolean)
Log.e("ganesh", "word deleted successfully!!!");
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
}
}, DeleteThisWord.Params.deleteThisWord(wordId));
}
public void updateThisWord(int wordId, String newWord) {
updateThisWord.execute(new DisposableObserver<Boolean>() {
@Override
public void onNext(Boolean aBoolean) {
if (aBoolean)
Log.e("ganesh", "word updated successfully!!!");
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
}
}, UpdateThisWord.Params.updateThisWord(wordId, newWord));
}
public MutableLiveData<List<Word>> getWords() {
if (allWords == null) {
allWords = new MutableLiveData<>();
}
return allWords;
}
@Override
protected void onCleared() {
super.onCleared();
if (getAllWords != null)
getAllWords = null;
if (deleteThisWord != null)
deleteThisWord = null;
if (insertWord != null)
insertWord = null;
if (updateThisWord != null)
updateThisWord = null;
if (getTheIndexOfTopWord != null)
getTheIndexOfTopWord = null;
}
}
数据层中的 DAO:
@Dao
public interface WordDao {
@Insert
void insertThisWord(Word word);
@Query("delete from word_table")
void deleteAll();
@Query("select * from word_table order by word_id asc")
List<Word> getAllWords();
@Query("delete from word_table where word_id = :wordId")
void deleteThisWord(int wordId);
@Query("update word_table set word = :newWord where word_id = :wordId")
void updateThisWord(int wordId, String newWord);
@Query("select * from word_table order by word_id asc limit 1")
Word getTheIndexOfTopWord();
}
数据层中的存储库:
public class WordRepositoryImpl implements WordRepository {
private ApiInterface apiInterface;
private SharedPreferenceHelper sharedPreferenceHelper;
private Context context;
private WordDao wordDao;
private WordRoomDatabase db;
public WordRepositoryImpl(ApiInterface apiInterface, SharedPreferenceHelper sharedPreferenceHelper, WordRoomDatabase db, Context context) {
this.apiInterface = apiInterface;
this.sharedPreferenceHelper = sharedPreferenceHelper;
this.context = context;
this.db = db;
wordDao = db.wordDao();
}
@Override
public Observable<Integer> sum(final int a, final int b) {
return Observable.fromCallable(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return (a + b);
}
});
}
@Override
public Observable<List<Word>> getAllWords() {
return Observable.fromCallable(new Callable<List<Word>>() {
@Override
public List<Word> call() throws Exception {
List<Word> list = new ArrayList<>();
List<com.example.data.models.Word> listWords = db.wordDao().getAllWords();
for (com.example.data.models.Word item : listWords) {
list.add(new Word(item.getWordId(), item.getWord(), item.getWordLength()));
}
return list;
}
});
}
@Override
public Observable<Boolean> insertThisWord(final Word word) {
return Observable.fromCallable(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
com.example.data.models.Word item = new com.example.data.models.Word(word.getWord(), word.getWordLength());
db.wordDao().insertThisWord(item);
return true;
}
});
}
@Override
public Observable<Boolean> deleteThisWord(final int wordId) {
return Observable.fromCallable(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
db.wordDao().deleteThisWord(wordId);
return true;
}
});
}
@Override
public Observable<Boolean> updateThisWord(final int wordId, final String newWord) {
return Observable.fromCallable(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
db.wordDao().updateThisWord(wordId, newWord);
return true;
}
});
}
@Override
public Observable<Word> getTheIndexOfTopWord() {
return Observable.fromCallable(new Callable<Word>() {
@Override
public Word call() throws Exception {
com.example.data.models.Word item = db.wordDao().getTheIndexOfTopWord();
Word word = new Word(item.getWordId(), item.getWord(), item.getWordLength());
return word;
}
});
}
}
领域层中的 GetAllWordsUseCase:
public class GetAllWords extends UseCase<List<Word>, GetAllWords.Params> {
private WordRepository wordRepository;
public GetAllWords(PostExecutionThread postExecutionThread, WordRepository wordRepository) {
super(postExecutionThread);
this.wordRepository = wordRepository;
}
@Override
public Observable<List<Word>> buildUseCaseObservable(Params params) {
return wordRepository.getAllWords();
}
public static final class Params {
private Params() {
}
public static GetAllWords.Params getAllWords() {
return new GetAllWords.Params();
}
}
}
领域层中的用例库Class:
public abstract class UseCase<T, Params> {
private final PostExecutionThread postExecutionThread;
private final CompositeDisposable compositeDisposable;
public UseCase(PostExecutionThread postExecutionThread) {
this.postExecutionThread = postExecutionThread;
this.compositeDisposable = new CompositeDisposable();
}
/**
* Builds an {@link Observable} which will be used when executing the current {@link UseCase}.
*/
public abstract Observable<T> buildUseCaseObservable(Params params);
/**
* Dispose from current {@link CompositeDisposable}.
*/
public void dispose() {
if (!compositeDisposable.isDisposed()) {
compositeDisposable.dispose();
}
}
/**
* Executes the current use case.
*
* @param observer {@link DisposableObserver} which will be listening to the observable build
* by {@link #buildUseCaseObservable(Params)} ()} method.
* @param params Parameters (Optional) used to build/execute this use case.
*/
public void execute(DisposableObserver<T> observer, Params params) {
if (observer != null) {
final Observable<T> observable = this.buildUseCaseObservable(params)
.subscribeOn(Schedulers.io())
.observeOn(postExecutionThread.getScheduler());
addDisposable(observable.subscribeWith(observer));
}
}
/**
* Dispose from current {@link CompositeDisposable}.
*/
private void addDisposable(Disposable disposable) {
if (disposable != null && compositeDisposable != null)
compositeDisposable.add(disposable);
}
}
最后,表示层中的WordActivity
public class WordActivity extends BaseActivity<WordViewModel> implements
View.OnClickListener, WordNavigator {
@Inject
WordViewModel wordViewModel;
private Button deleteButton, updateButton, addButton;
private EditText editTextWord;
private WordListAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_word);
((MainApplication) getApplicationContext()).getComponent().inject(this);
editTextWord = findViewById(R.id.activity_word_et_word);
deleteButton = findViewById(R.id.activity_main_delete_button);
updateButton = findViewById(R.id.activity_main_update_button);
addButton = findViewById(R.id.activity_word_btn_add_word);
deleteButton.setOnClickListener(this);
updateButton.setOnClickListener(this);
addButton.setOnClickListener(this);
RecyclerView recyclerView = findViewById(R.id.recyclerview);
adapter = new WordListAdapter(this);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
getViewModel().setNavigator(this);
getViewModel().getAllWords();
getViewModel().getWords().observe(this, new Observer<List<Word>>() {
@Override
public void onChanged(@android.support.annotation.Nullable List<Word> words) {
adapter.setWords(words);
}
});
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.activity_main_delete_button:
getViewModel().getTheIndexOfTopWord(TOP_INDEX_ACTION_DELETE);
break;
case R.id.activity_main_update_button:
getViewModel().getTheIndexOfTopWord(TOP_INDEX_ACTION_UPDATE);
break;
case R.id.activity_word_btn_add_word:
handleAddButtonClick();
break;
}
}
public void handleAddButtonClick() {
String text = editTextWord.getText().toString();
if (text.equals("")) {
Toast.makeText(getApplicationContext(), R.string.empty_not_saved, Toast.LENGTH_LONG).show();
} else {
Word word = new Word(text, text.length());
getViewModel().insertWord(word);
editTextWord.setText("");
editTextWord.clearFocus();
}
}
@Override
public void updateTopIndex(Integer wordId, String action) {
if (action.equals(TOP_INDEX_ACTION_DELETE))
getViewModel().deleteThisWord(wordId);
else
getViewModel().updateThisWord(wordId, "dsakagdad");
}
@Override
public WordViewModel getViewModel() {
return wordViewModel;
}
}
**getViewModel().getWords().observe(this, new Observer<List<Word>>() {
@Override
public void onChanged(@android.support.annotation.Nullable List<Word> words) {
adapter.setWords(words);
}
});**
//This portion is getting called only once but not when I
insert/update/delete words from room database!
任何人都可以通过这些并帮助我在这里!
DAO 中的这个方法将查询列表,return 它就像一个普通的 SQL 查询:
@Query("select * from word_table order by word_id asc")
List<Word> getAllWords();
如果您想观察变化,您可能需要考虑使用 RxJava2 Flowable/Observable
或 LiveData
。
因为我更喜欢 RxJava 方法,它看起来像这样:
@Query("select * from word_table order by word_id asc")
Flowable<List<Word>> getAllWords();
// or
Observable<List<Word>> getAllWords();
完成后,您可能想将存储库中的 getAllWords
方法更改为 return 即 Flowable/Observable
.
注意:使用 Observable
或 Flowable
两者都会最初发出一次查询结果,然后开始观察进一步的变化,直到取消订阅。