Обновить данные архитектуры MVVM - PullRequest
0 голосов
/ 31 октября 2018

У меня есть реализация MVVM для извлечения данных из Интернета с использованием Retrofit2, Rxjava и Rxandroid.

Моя цель - обновить данные, когда пользователь проводит пальцем по SwipeRefreshLayout. Это реализация.

NewsFeedFragment.java

@Inject
ViewModelFactory viewModelFactory;
RandomVideosViewModel viewModel;


@Override
public void onAttach(Context context) {
    ((BaseApplication) context.getApplicationContext())
            .getAppComponent()
            .inject(this);
    super.onAttach(context);
}

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    ... 

    viewModel = ViewModelProviders.of(this, viewModelFactory).get(RandomVideosViewModel.class);

    VideoCardAdapter videoCardAdapter = new VideoCardAdapter(getActivity());

    viewModel.videosList.observe(this, videoCardAdapter::submitList);
    viewModel.networkState.observe(this, videoCardAdapter::setNetworkState);

    mRecyclerView.setAdapter(videoCardAdapter);

    ...
}

RandomVideosViewModel.java

public class RandomVideosViewModel extends ViewModel {

    public LiveData<PagedList<Video>> videosList;
    public LiveData<NetworkState> networkState;

    public RandomVideosViewModel(RandomVideosDataSourceFactory randomVideosDataSourceFactory) {

        networkState = Transformations.switchMap(randomVideosDataSourceFactory.getMutableLiveData(),
                PageKeyedRandomVideosDataSource::getNetworkState);

        PagedList.Config pagedListConfig = (new PagedList.Config.Builder()
                .setEnablePlaceholders(false)
                .setInitialLoadSizeHint(10)
                .setPageSize(10))
                .build();

        videosList = (new LivePagedListBuilder(randomVideosDataSourceFactory, pagedListConfig)).build();
    }

}

RandomVideosDataSourceFactory

public class RandomVideosDataSourceFactory extends DataSource.Factory {

    private MutableLiveData<PageKeyedRandomVideosDataSource> mutableLiveData = new MutableLiveData<>();
    private PageKeyedRandomVideosDataSource pageKeyedRandomVideosDataSource;

    public RandomVideosDataSourceFactory(PageKeyedRandomVideosDataSource pageKeyedRandomVideosDataSource) {
        this.pageKeyedRandomVideosDataSource = pageKeyedRandomVideosDataSource;
    }

    public MutableLiveData<PageKeyedRandomVideosDataSource> getMutableLiveData() {
        return mutableLiveData;
    }

    @Override
    public DataSource create() {
        mutableLiveData.postValue(pageKeyedRandomVideosDataSource);
        return pageKeyedRandomVideosDataSource;
    }
}

PageKeyedRandomVideosDataSource

public class PageKeyedRandomVideosDataSource extends PageKeyedDataSource<Integer, Video> {

    private static final String TAG = "Refresh - PageKeyedRand";

    private CompositeDisposable disposable = new CompositeDisposable();
    private MutableLiveData<NetworkState> networkState = new MutableLiveData<>();
    private MutableLiveData<NetworkState> initialLoading = new MutableLiveData<>();
    private Repository repository;
    private Random random = new Random();
    private int firstPage;
    private List<Integer> usedNumbers = new ArrayList<>();
    private int numbOfTimes = 0;

    public PageKeyedRandomVideosDataSource(Repository repository) {
        this.repository = repository;
    }

    public MutableLiveData<NetworkState> getNetworkState() {
        return networkState;
    }

    public MutableLiveData<NetworkState> getInitialLoading() {
        return initialLoading;
    }

    @Override
    public void
    loadInitial(@NonNull LoadInitialParams<Integer> params, @NonNull LoadInitialCallback<Integer, Video> callback) {
        List<Video> videoList = new ArrayList<>();
        networkState.postValue(NetworkState.LOADING);
        initialLoading.postValue(NetworkState.LOADING);

        firstPage = getFirstPage();
        usedNumbers.add(firstPage);
        numbOfTimes++;

        Log.i(TAG, "loadInitial: Loading page: " + firstPage + " - Size: " + params.requestedLoadSize);

        disposable.add(RxHelper.getObservable(repository.getHomeVideosObservable(params.requestedLoadSize, firstPage))
                .subscribe(requestVideo -> {
                    if (requestVideo != null) {
                        int lastPage = requestVideo.getLastPage();
                        int nextPage = getRandomPage(lastPage);
                        Log.i(TAG, "loadInitial: NextPage: " + nextPage);

                        videoList.addAll(requestVideo.getVideoList());
                        callback.onResult(videoList, null, nextPage);
                        networkState.postValue(NetworkState.LOADED);
                        initialLoading.postValue(NetworkState.LOADED);
                    }
                }, throwable -> {
                    throwable.printStackTrace();
                    networkState.postValue(NetworkState.failed(throwable.getMessage()));
                    initialLoading.postValue(NetworkState.failed(throwable.getMessage()));
                }));
    }

    @Override
    public void loadBefore(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, Video> callback) {

    }

    @Override
    public void loadAfter(@NonNull LoadParams<Integer> params, @NonNull LoadCallback<Integer, Video> callback) {
        Log.i(TAG, "loadAfter: Loading page: " + params.key + " - Size: " + params.requestedLoadSize);
        List<Video> videoList = new ArrayList<>();
        networkState.postValue(NetworkState.LOADING);

        disposable.add(RxHelper.getObservable(repository.getHomeVideosObservable(params.requestedLoadSize, params.key))
                .subscribe(requestVideo -> {
                    if (requestVideo != null) {
                        int lastPage = requestVideo.getLastPage();
                        int nextPage = getRandomPage(lastPage);
                        Log.i(TAG, "loadAfter: NextPage: " + nextPage);

                        videoList.addAll(requestVideo.getVideoList());
                        callback.onResult(videoList, nextPage);
                        networkState.postValue(NetworkState.LOADED);
                    }
                }, throwable -> {
                    throwable.printStackTrace();
                    networkState.postValue(NetworkState.failed(throwable.getMessage()));
                }));
    }

RandomVideosDataSourceFactory просто извлекает источник PageKeyedRandomVideosDataSource, и этот последний загружает данные в виде фрагмента страниц.

Вопрос

После загрузки этих данных я не нахожу способа обновить их, когда пользователь использует SwipeRefreshLayout. Любая подсказка?

Что я пробовал

Я пытался воссоздать ViewModel, но, похоже, он продолжает получать тот же экземпляр.

1 Ответ

0 голосов
/ 31 октября 2018

Как правило, лучшим способом является сбор абстрактных данных из ViewModel путем помещения их в репозиторий.

Репозиторий является синглтоном. У него есть LiveData, которые ViewModel наблюдает.

Репозиторий изначально получает данные из кеша (например, Room). Он также наблюдает за этими данными.

Когда вам нужен новый набор данных (первая загрузка, сканирование при обновлении или даже рабочий), вы вызываете свой репозиторий, чтобы начать обновление кэша. Это автоматически обновит данные в вашей ViewModel (и все остальное, что наблюдает за ViewModel).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...