title: NetworkBoundResource helper class without Room
body: <p>When I tried to implements the <code>NetworkBoundResource</code> and <code>Resource</code> helper class for the Room Db and Retrofit, it works perfect. However, I need to implement the Search Result from RESTful using <strong>Retrofit only without Room</strong>. The <code>Resources</code> class is good and I dont need to change it. What I want to do is try to remove db source inside this class. </p>
  
  <pre><code>public abstract class NetworkBoundResource&lt;ResultType, RequestType&gt; {
    private final AppExecutors appExecutors;
  
    private final MediatorLiveData&lt;Resource&lt;ResultType&gt;&gt; result = new MediatorLiveData&lt;&gt;();
  
    @MainThread
    public NetworkBoundResource(AppExecutors appExecutors) {
      this.appExecutors = appExecutors;
      result.setValue(Resource.loading(null));
      LiveData&lt;ResultType&gt; dbSource = loadFromDb();
      result.addSource(dbSource, data -&gt; {
        result.removeSource(dbSource);
        if (shouldFetch(data)) {
          fetchFromNetwork(dbSource);
        } else {
          result.addSource(dbSource, newData -&gt; setValue(Resource.success(newData)));
        }
      });
    }
  
    @MainThread
    private void setValue(Resource&lt;ResultType&gt; newValue) {
      if (!Objects.equals(result.getValue(), newValue)) {
        result.setValue(newValue);
      }
    }
  
    private void fetchFromNetwork(final LiveData&lt;ResultType&gt; dbSource) {
      LiveData&lt;ApiResponse&lt;RequestType&gt;&gt; apiResponse = createCall();
      // we re-attach dbSource as a new source, it will dispatch its latest value quickly
      result.addSource(dbSource, newData -&gt; setValue(Resource.loading(newData)));
      result.addSource(apiResponse, response -&gt; {
        result.removeSource(apiResponse);
        result.removeSource(dbSource);
        //noinspection ConstantConditions
        if (response.isSuccessful()) {
          appExecutors.diskIO().execute(() -&gt; {
            saveCallResult(processResponse(response));
            appExecutors.mainThread().execute(() -&gt;
                // 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 -&gt; setValue(Resource.success(newData)))
            );
          });
        } else {
          onFetchFailed();
          result.addSource(dbSource,
              newData -&gt; setValue(Resource.error(response.errorMessage, newData)));
        }
      });
    }
  
    protected void onFetchFailed() {
    }
  
    public LiveData&lt;Resource&lt;ResultType&gt;&gt; asLiveData() {
      return result;
    }
  
    @WorkerThread
    protected RequestType processResponse(ApiResponse&lt;RequestType&gt; response) {
      return response.body;
    }
  
    @WorkerThread
    protected abstract void saveCallResult(@NonNull RequestType item);
  
    @MainThread
    protected abstract boolean shouldFetch(@Nullable ResultType data);
  
    @NonNull
    @MainThread
    protected abstract LiveData&lt;ResultType&gt; loadFromDb();
  
    @NonNull
    @MainThread
    protected abstract LiveData&lt;ApiResponse&lt;RequestType&gt;&gt; createCall();
  }
  </code></pre>