Как обновить пользовательский интерфейс с ответом на ошибку сети в MVVM, используя NetworkBoundResource - PullRequest
2 голосов
/ 29 февраля 2020

Я пытаюсь реализовать шаблон MVVM, используя компоненты архитектуры Google android, в то время как RX Java в NetworkBoundResource. Однако мне трудно найти способ передать ответ об ошибке сетевого вызова на активность. Вот ссылка на оригинальный проект github .

. Я читал этот пост о " рефакторинге класса Google NetworkBoundResource для использования Rx Java вместо LiveData ", но до сих пор не ясно, как на самом деле решить проблему. был бы признателен, если бы вы могли направить меня к решению на основе кода для этого сценария для лучшего понимания.

ура!

GithubRepository:

@Singleton
public class GithubRepository {

    private GithubDao githubDao;
    private GithubApiService githubApiService;

    public GithubRepository(GithubDao githubDao, GithubApiService githubApiService) {
        this.githubDao = githubDao;
        this.githubApiService = githubApiService;
    }

    public Observable<Resource<List<GithubEntity>>> getRepositories(Long page) {
        return new NetworkBoundResource<List<GithubEntity>, GithubApiResponse>() {

            @Override
            protected void saveCallResult(@NonNull GithubApiResponse item) {
                List<GithubEntity> repositories = item.getItems();
                for (GithubEntity githubEntity : repositories) {
                    githubEntity.setPage(page);
                    githubEntity.setTotalPages(item.getTotalCount());
                }
                githubDao.insertRepositories(repositories);
            }

            @Override
            protected boolean shouldFetch() {
                return true;
            }

            @NonNull
            @Override
            protected Flowable<List<GithubEntity>> loadFromDb() {
                List<GithubEntity> repositories = githubDao.getRepositoriesByPage(page);
                return (repositories == null || repositories.isEmpty()) ?
                        Flowable.empty() : Flowable.just(repositories);
            }

            @NonNull
            @Override
            protected Observable<Resource<GithubApiResponse>> createCall() {
                return githubApiService.fetchRepositories(QUERY_SORT, QUERY_ORDER, page)
                        .flatMap(response ->
                                Observable.just(response.isSuccessful()
                                        ? Resource.success(response.body())
                                        : Resource.error("", new GithubApiResponse())));
            }

        }.getAsObservable();
    }
}

.: ОБНОВЛЕНИЕ:. Итак, я вижу, что в NetworkBoundResource the doOnError и onErrorResumeNext обрабатывают ответ об ошибке. но я не знаю, как получить этот ответ в деятельности. Мне трудно это понять.

NetworkBoundResource:

public abstract class NetworkBoundResource<ResultType, RequestType> {

    private Observable<Resource<ResultType>> result;

    @MainThread
    protected NetworkBoundResource() {
        Observable<Resource<ResultType>> source;
        if (shouldFetch()) {
            source = createCall()
                    .subscribeOn(Schedulers.io())
                    .doOnNext(apiResponse -> saveCallResult(processResponse(apiResponse)))
                    .flatMap(apiResponse -> loadFromDb().toObservable().map(Resource::success))
                    .doOnError(t -> onFetchFailed())
                    .onErrorResumeNext(t -> {
                        return loadFromDb()
                                .toObservable()
                                .map(data -> Resource.error(t.getMessage(), data));

                    })
                    .observeOn(AndroidSchedulers.mainThread());
        } else {
            source = loadFromDb()
                    .toObservable()
                    .map(Resource::success);
        }

        result = Observable.concat(
                loadFromDb()
                        .toObservable()
                        .map(Resource::loading)
                        .take(1),
                source
        );
    }

    public Observable<Resource<ResultType>> getAsObservable() {return result;}

    protected void onFetchFailed() {}

    @WorkerThread
    protected RequestType processResponse(Resource<RequestType> response) {return response.data;}

    @WorkerThread
    protected abstract void saveCallResult(@NonNull RequestType item);

    @MainThread
    protected abstract boolean shouldFetch();

    @NonNull
    @MainThread
    protected abstract Flowable<ResultType> loadFromDb();

    @NonNull
    @MainThread
    protected abstract Observable<Resource<RequestType>> createCall();
}

GithubListViewModel :

public class GithubListViewModel extends ViewModel {

    private Long currentPage = 0l;
    private GithubRepository repository;

    private List<GithubEntity> repositories = new ArrayList<>();
    private SingleLiveEvent<List<GithubEntity>> repoListLiveData = new SingleLiveEvent<>();

    @Inject
    public GithubListViewModel(GithubDao githubDao, GithubApiService githubApiService) {
        repository = new GithubRepository(githubDao, githubApiService);
    }

    public void fetchRepositories() {
        repository.getRepositories(++currentPage)
                .subscribe(resource -> {
                    if(resource.isLoaded()) {
                        repositories.addAll(resource.data);
                        getRepositoryListLiveData().postValue(resource.data);
                    }
                });
    }


    public List<GithubEntity> getRepositories() {
        return repositories;
    }

    public SingleLiveEvent<List<GithubEntity>> getRepositoryListLiveData() {
        return repoListLiveData;
    }

    public boolean isLastPage() {
        return getRepositoryListLiveData().getValue() != null &&
                !getRepositoryListLiveData().getValue().isEmpty() ?
                getRepositoryListLiveData().getValue().get(0).isLastPage() :
                false;
    }
}

GithubActivity:

public class GithubListActivity extends AppCompatActivity implements RecyclerLayoutClickListener {

...

    private void initialiseViewModel() {
        githubListViewModel = ViewModelProviders.of(this, viewModelFactory).get(GithubListViewModel.class);
        githubListViewModel.getRepositoryListLiveData().observe(this, repositories -> {
            if(githubListAdapter.getItemCount() == 0) {
                if(!repositories.isEmpty()) {
                    animateView(repositories);

                } else displayEmptyView();

            } else if(!repositories.isEmpty()) displayDataView(repositories);
        });
    }
...

githubListViewModel.fetchRepositories();

...
}
...