-->

How to update UI with network error response in MV

2020-07-27 06:04发布

问题:

I'm trying to implement MVVM pattern usingGoogle's android architecture components while using RX Java in NetworkBoundResource. However I'm having a difficult time finding a way to communicate the error response from network call to activity. here is a link to the original github project.

I have read this post about "Refactoring google's NetworkBoundResource class to use RxJava instead of LiveData" but still not clear how to actually solve the problem. would appreciate if you could direct me to a code based solution for this scenario for better understanding.

cheers!

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

.:UPDATE:. So I can see that the the in NetworkBoundResource the doOnError and onErrorResumeNext are handling the error response. but i don't know how to get this response in the activity. I am having a hard time understanding it.

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

...
}