Architecture-components-samples: NetworkBoundResource - Can we use it if we are not saving the API response to a Room DB?

Created on 3 Aug 2017  路  7Comments  路  Source: android/architecture-components-samples

It seems NetworkBoundResource works on the bases that, the data is stored in the DB. I have data I want to fetch from an API, however this data won't be stored in the DB as it does not need to live longer than the users session on the activity lifecycle. How could we still use NetworkBoundResource in this case?

Most helpful comment

Of course. I will use UserRepository for simplicity's sake. In loadUser(String login), Notice this method returns LiveData<Resource<User>>, and GithubSerivce#getUser() returns LiveData<ApiResponse<User>>, which is very similiar, I removed the Resource wrapper and made the both methods returns LiveData<ApiResponse<List<Repo>>>.

Consequently, the UserRepository#getuser(String login) became like this. and that doesn't affect UserViewModel or LiveDataCallAdapter

public LiveData<Resource<User>> loadUser(String login) {
        return githubService.getUser(login);
}

So, what I did is totally removing NetworkBoundResource, some might have objection for that, cuz Resource<T> can handle some network errors. So, I change the ApiResponse<T> to handle some errors.

public final class ApiResponse<V> {

    @Nullable
    private final V data;

    @Nullable
    private final Throwable error;

    /**
     * In Case of successful API request, pass the received data here.
     *
     * @param Data received data from successful API Call.
     */
    public ApiResponse(@NonNull final V Data) {
        Objects.requireNonNull(Data);

        this.data = Data;
        this.error = null;
    }

    /**
     * In case of failed API request, pass error.
     * @param error The cause of the failed API Call.
     */
    public ApiResponse(@NonNull final Throwable error) {
        Objects.requireNonNull(error);

        this.error = error;
        this.data = null;
    }

    public boolean isSuccessful() {
        return data != null && error == null;
    }

    @NonNull
    public V getData() {
        if (data == null) {
            throw new IllegalStateException("Data is null; Call ApiResponse#isSuccessful() first.");
        }
        return data;
    }

    @NonNull
    public Throwable getError() {
        if (error == null) {
            throw new IllegalStateException("error is null; Call ApiResponse#isSuccessful() first.");
        }
        return error;
    }
}

ApiResponse<V> either has data or error and more simple.

However, if you want to keep the Resource<T> wrapper, the turn around for that is editing NetworkBoundResource and change the logic by removing db related actions and shouldFetch() will be always true, BUT I guess NetworkBoundResource became useless and more complex.

All 7 comments

To answer my own question, what I have come up with is to build a cache class, that the repository also knows about and in cases where I dont need data saved to the DB, I store it in the cache. The cache class returns the data using LiveData signals and this works well with the NetworkBoundResource methods.

If there is a better way of doing this, I would love to hear it.

If you don't have to cache, you don't need it at all. I used the service directly in the repository and it worked seamlessly.

That sounds great. Could you give me an example if possible? Would really appreciate! Thanks

Of course. I will use UserRepository for simplicity's sake. In loadUser(String login), Notice this method returns LiveData<Resource<User>>, and GithubSerivce#getUser() returns LiveData<ApiResponse<User>>, which is very similiar, I removed the Resource wrapper and made the both methods returns LiveData<ApiResponse<List<Repo>>>.

Consequently, the UserRepository#getuser(String login) became like this. and that doesn't affect UserViewModel or LiveDataCallAdapter

public LiveData<Resource<User>> loadUser(String login) {
        return githubService.getUser(login);
}

So, what I did is totally removing NetworkBoundResource, some might have objection for that, cuz Resource<T> can handle some network errors. So, I change the ApiResponse<T> to handle some errors.

public final class ApiResponse<V> {

    @Nullable
    private final V data;

    @Nullable
    private final Throwable error;

    /**
     * In Case of successful API request, pass the received data here.
     *
     * @param Data received data from successful API Call.
     */
    public ApiResponse(@NonNull final V Data) {
        Objects.requireNonNull(Data);

        this.data = Data;
        this.error = null;
    }

    /**
     * In case of failed API request, pass error.
     * @param error The cause of the failed API Call.
     */
    public ApiResponse(@NonNull final Throwable error) {
        Objects.requireNonNull(error);

        this.error = error;
        this.data = null;
    }

    public boolean isSuccessful() {
        return data != null && error == null;
    }

    @NonNull
    public V getData() {
        if (data == null) {
            throw new IllegalStateException("Data is null; Call ApiResponse#isSuccessful() first.");
        }
        return data;
    }

    @NonNull
    public Throwable getError() {
        if (error == null) {
            throw new IllegalStateException("error is null; Call ApiResponse#isSuccessful() first.");
        }
        return error;
    }
}

ApiResponse<V> either has data or error and more simple.

However, if you want to keep the Resource<T> wrapper, the turn around for that is editing NetworkBoundResource and change the logic by removing db related actions and shouldFetch() will be always true, BUT I guess NetworkBoundResource became useless and more complex.

@amrro Thanks for the sample and explanation. This does indeed look like a good solution. However, in some cases, I need the Repo to decide, if it should fetch from a DB or from the network. I think in my case, I might need to keep NetworkBoundResource. I will try implement some of your recommendations though.

@amrro and @RJ-Clegg Can you tell me how to add loader if i don't want to use NetworkBoundResource ?

Was this page helpful?
0 / 5 - 0 ratings