Как преобразовать обычные данные (возвращенные из комнаты) в LiveData на слое ViewModel - PullRequest
0 голосов
/ 30 августа 2018

Я использую чистую архитектуру с шаблоном MVVM, поэтому часть комнаты переходит на уровень данных, и я возвращаю наблюдаемые оттуда на уровень домена и использую их на уровне представления, оборачивая их в LiveData. Теперь проблема в том, что после вставки / удаления / обновления список не обновляется немедленно в интерфейсе пользователя.

Модель представления в слое презентации:

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

Базовый класс UseCase в доменном слое:

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!

Может кто-нибудь пройти через это и помочь мне здесь!

1 Ответ

0 голосов
/ 31 августа 2018

Этот метод в DAO будет запрашивать список и возвращать его как обычный запрос 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 в хранилище, чтобы вернуть Flowable/Observable.

Примечание. При использовании Observable или Flowable оба будут сначала отправлять результат запроса один раз, а затем начнут наблюдать за дальнейшими изменениями, пока не откажутся от подписки.

Подробнее о Комната с RxJava

...