android / architecture-components-samples

Samples for Android Architecture Components.
https://d.android.com/arch
Apache License 2.0
23.42k stars 8.29k forks source link

NetworkBoundResource: Why load live data object of db another time? #199

Open philipp-mohr opened 6 years ago

philipp-mohr commented 6 years ago

Why is loadFromDb() called another time after network data is fetched successfully? Why can't we use dbSource live data object again?

The way I understand live data object of a database is that if we extract it once, all changes in db will be notified to the observer. If this is correct dbSource can replace loadFromDb(), right?

NetworkBoundResource.class:

private void fetchFromNetwork(final LiveData<ResultType> dbSource) {
        LiveData<ApiResponse<RequestType>> apiResponse = createCall();
        // we re-attach dbSource as a new source, it will dispatch its latest value quickly
        result.addSource(dbSource, newData -> result.setValue(Resource.loading(newData)));
        result.addSource(apiResponse, response -> {
            result.removeSource(apiResponse);
            result.removeSource(dbSource);
            //noinspection ConstantConditions
            if (response.isSuccessful()) {
                appExecutors.diskIO().execute(() -> {
                    saveCallResult(processResponse(response));
                    appExecutors.mainThread().execute(() ->
                            // we specially request a new live data,
                            // otherwise we will get immediately last cached value,
                            // which may not be updated with latest results received from network.
                            result.addSource(loadFromDb(),
                                    newData -> result.setValue(Resource.success(newData)))
                    );
                });
            } else {
                onFetchFailed();
                result.addSource(dbSource,
                        newData -> result.setValue(Resource.error(response.errorMessage, newData)));
            }
        });
    }
philipp-mohr commented 6 years ago

Okay, I have a suspicion: result.removeSource(dbSource) disconnects the dbSource from result live data. Then the change in db happens due to insertion of new network data. When we reconnect to dbSource nothing will be emitted because result live data was disconnected when the change happened.

This issue is resolved by extracting a new db live data object using loadFromDb(). Right?

When the network call fails don't we need to call loadFromDb() as well, to communicate the Resource.error immediately? If we use dbSource there I would expect that the Resource.error is not emmitted immediatly, since the dbSource data does not change.

gaurav414u commented 6 years ago

@JoseAlcerreca Would you like to add something?

ipcjs commented 6 years ago

@piveloper If dbSource has already emitted a value, result.addSource(dbSource) will emit cache value. result.addSource(loadFromDb()) will emit newly Value.