title: Android NetworkBoundResource using repository pattern API error
body: <p>Hi I am just started with mvvm with repository pattern I am stuck with the API error 
  I am using the generic API Response class as per google official repo in java </p>
  
  <pre><code>/**
   * Generic class for handling responses from Retrofit
   *
   * @param &lt;T&gt;
   */
  public class ApiResponse&lt;T&gt; {
  
      public ApiResponse&lt;T&gt; create(Throwable error) {
          return new ApiErrorResponse&lt;&gt;(error.getMessage().equals("") ? error.getMessage() : "Unknown error\nCheck network connection");
      }
  
      public ApiResponse&lt;T&gt; create(Response&lt;T&gt; response) {
  
          if (response.isSuccessful()) {
              T body = response.body();
  
              if (body instanceof GithubApiResponse) {
                  if (AppUtils.isValid((GithubApiResponse) body)) {
                      String errorMsg = "Empty Response.";
                      return new ApiErrorResponse&lt;&gt;(errorMsg);
                  }
              }
  
              if (body == null || response.code() == 204) { // 204 is empty response
                  return new ApiEmptyResponse&lt;&gt;();
              } else {
                  return new ApiSuccessResponse&lt;&gt;(body);
              }
          } else {
              String errorMsg = "";
              try {
                  errorMsg = response.errorBody().string();
              } catch (IOException e) {
                  e.printStackTrace();
                  errorMsg = response.message();
              }
              return new ApiErrorResponse&lt;&gt;(errorMsg);
          }
      }
  
      /**
       * Generic success response from api
       *
       * @param &lt;T&gt;
       */
      public class ApiSuccessResponse&lt;T&gt; extends ApiResponse&lt;T&gt; {
  
          private T body;
  
          ApiSuccessResponse(T body) {
              this.body = body;
          }
  
          public T getBody() {
              return body;
          }
  
      }
  
      /**
       * Generic Error response from API
       *
       * @param &lt;T&gt;
       */
      public class ApiErrorResponse&lt;T&gt; extends ApiResponse&lt;T&gt; {
  
          private String errorMessage;
  
          ApiErrorResponse(String errorMessage) {
              this.errorMessage = errorMessage;
          }
  
          public String getErrorMessage() {
              return errorMessage;
          }
  
      }
  
  
      /**
       * separate class for HTTP 204 resposes so that we can make ApiSuccessResponse's body non-null.
       */
      public class ApiEmptyResponse&lt;T&gt; extends ApiResponse&lt;T&gt; {
      }
  
  }
  </code></pre>
  
  <p>and My <strong>networkBoundResource</strong> as like this  </p>
  
  <pre><code>public abstract class NetworkBoundResource&lt;ResultType, RequestType&gt; {
  
      private AppExecutors appExecutors;
      private MediatorLiveData&lt;Resource&lt;ResultType&gt;&gt; results = new MediatorLiveData&lt;&gt;();
  
      public NetworkBoundResource(AppExecutors appExecutors) {
          this.appExecutors = appExecutors;
          init();
      }
  
  
      private void init() {
  
          // update LiveData for loading status
          results.setValue((Resource&lt;ResultType&gt;) Resource.loading(null));
  
          // observe LiveData source from local db
          final LiveData&lt;ResultType&gt; dbSource = loadFromDb();
  
          results.addSource(dbSource, new Observer&lt;ResultType&gt;() {
              @Override
              public void onChanged(@Nullable ResultType ResultType) {
  
                  results.removeSource(dbSource);
  
                  if (shouldFetch(ResultType)) {
                      // get data from the network
                      fetchFromNetwork(dbSource);
                  } else {
                      results.addSource(dbSource, new Observer&lt;ResultType&gt;() {
                          @Override
                          public void onChanged(@Nullable ResultType ResultType) {
                              setValue(Resource.success(ResultType));
                          }
                      });
                  }
              }
          });
      }
  
      /**
       * 1) observe local db
       * 2) if &lt;condition/&gt; query the network
       * 3) stop observing the local db
       * 4) insert new data into local db
       * 5) begin observing local db again to see the refreshed data from network
       *
       * @param dbSource
       */
      private void fetchFromNetwork(final LiveData&lt;ResultType&gt; dbSource) {
  
          Timber.d("fetchFromNetwork: called.");
  
          // update LiveData for loading status
          results.addSource(dbSource, new Observer&lt;ResultType&gt;() {
              @Override
              public void onChanged(@Nullable ResultType ResultType) {
                  setValue(Resource.loading(ResultType));
              }
          });
  
          final LiveData&lt;ApiResponse&lt;RequestType&gt;&gt; apiResponse = createCall();
  
          results.addSource(apiResponse, new Observer&lt;ApiResponse&lt;RequestType&gt;&gt;() {
              @Override
              public void onChanged(@Nullable final ApiResponse&lt;RequestType&gt; requestObjectApiResponse) {
                  results.removeSource(dbSource);
                  results.removeSource(apiResponse);
  
                  /*
                      3 cases:
                         1) ApiSuccessResponse
                         2) ApiErrorResponse
                         3) ApiEmptyResponse
                   */
  
                  if (requestObjectApiResponse instanceof ApiResponse.ApiSuccessResponse) {
                      Timber.d("onChanged: ApiSuccessResponse.");
  
                      appExecutors.diskIO().execute(new Runnable() {
                          @Override
                          public void run() {
  
                              // save the response to the local db
                              saveCallResult((RequestType) processResponse((ApiResponse.ApiSuccessResponse) requestObjectApiResponse));
  
                              appExecutors.mainThread().execute(new Runnable() {
                                  @Override
                                  public void run() {
                                      results.addSource(loadFromDb(), new Observer&lt;ResultType&gt;() {
                                          @Override
                                          public void onChanged(@Nullable ResultType ResultType) {
                                              setValue(Resource.success(ResultType));
                                          }
                                      });
                                  }
                              });
                          }
                      });
                  } else if (requestObjectApiResponse instanceof ApiResponse.ApiEmptyResponse) {
                      Timber.d("onChanged: ApiEmptyResponse");
                      appExecutors.mainThread().execute(new Runnable() {
                          @Override
                          public void run() {
                              results.addSource(loadFromDb(), new Observer&lt;ResultType&gt;() {
                                  @Override
                                  public void onChanged(@Nullable ResultType ResultType) {
                                      setValue(Resource.success(ResultType));
                                  }
                              });
                          }
                      });
                  } else if (requestObjectApiResponse instanceof ApiResponse.ApiErrorResponse) {
                      Timber.d("onChanged: ApiErrorResponse.");
                      results.addSource(dbSource, new Observer&lt;ResultType&gt;() {
                          @Override
                          public void onChanged(@Nullable ResultType ResultType) {
  
                              setValue(
                                      Resource.error(
                                              ((ApiResponse.ApiErrorResponse) requestObjectApiResponse).getErrorMessage(),
                                              ResultType
                                      )
                              );
                          }
                      });
                  }
              }
          });
      }
  
      private ResultType processResponse(ApiResponse.ApiSuccessResponse response) {
          return (ResultType) response.getBody();
      }
  
      private void setValue(Resource&lt;ResultType&gt; newValue) {
          if (results.getValue() != newValue) {
              results.setValue(newValue);
          }
      }
  
      // Called to save the result of the API response into the database.
      @WorkerThread
      protected abstract void saveCallResult(@NonNull RequestType item);
  
      // Called with the data in the database to decide whether to fetch
      // potentially updated data from the network.
      @MainThread
      protected abstract boolean shouldFetch(@Nullable ResultType data);
  
      // Called to get the cached data from the database.
      @NonNull
      @MainThread
      protected abstract LiveData&lt;ResultType&gt; loadFromDb();
  
      // Called to create the API call.
      @NonNull
      @MainThread
      protected abstract LiveData&lt;ApiResponse&lt;RequestType&gt;&gt; createCall();
  
      // Returns a LiveData object that represents the resource that's implemented
      // in the base class.
      public final LiveData&lt;Resource&lt;ResultType&gt;&gt; getAsLiveData() {
          return results;
      }
  
  }
  </code></pre>
  
  <p>my <strong>Repository</strong> looks like this </p>
  
  <pre><code>@Singleton
  public class GithubRepository {
  
      private GithubDao githubDao;
      private GithubTrendingApiService githubApiService;
  
      public GithubRepository(GithubDao githubDao, GithubTrendingApiService githubApiService) {
          this.githubDao = githubDao;
          this.githubApiService = githubApiService;
      }
  
      public LiveData&lt;Resource&lt;List&lt;GithubEntity&gt;&gt;&gt; getRepositories() {
          return new NetworkBoundResource&lt;List&lt;GithubEntity&gt;, GithubApiResponse&gt;(AppExecutors.getInstance()) {
  
              @Override
              protected void saveCallResult(@NonNull GithubApiResponse item) {
                  List&lt;GithubEntity&gt; repositories = item.getItems();
  
                  githubDao.insertRepositories(repositories);
              }
  
              @Override
              protected boolean shouldFetch(@Nullable List&lt;GithubEntity&gt; data) {
  //                Timber.d("shouldFetch: repo: " + data.toString());
  //                int currentTime = (int) (System.currentTimeMillis() / 1000);
  //                Timber.d("shouldFetch: current time: " + currentTime);
  //                int lastRefresh = data.getTimestamp();
  //                Timber.d("shouldFetch: last refresh: " + lastRefresh);
  //                Timber.d("shouldFetch: it's been " + ((currentTime - lastRefresh) / 60 / 60 / 24) +
  //                        " days since this recipe was refreshed. 30 days must elapse before refreshing. ");
  //                if ((currentTime - data.getTimestamp()) &gt;= Constants.RECIPE_REFRESH_TIME) {
  //                    Timber.d("shouldFetch: SHOULD REFRESH RECIPE?! " + true);
  //                    return true;
  //                }
  //                Timber.d("shouldFetch: SHOULD REFRESH RECIPE?! " + false);
                  return true;
              }
  
  
              @NonNull
              @Override
              protected LiveData&lt;List&lt;GithubEntity&gt;&gt; loadFromDb() {
                  return githubDao.getTrendingRepository();
              }
  
              @NonNull
              @Override
              protected LiveData&lt;ApiResponse&lt;GithubApiResponse&gt;&gt; createCall() {
                  return githubApiService.fetchTrendingRepositories();
              }
  
          }.getAsLiveData();
      }
  }
  </code></pre>
  
  <p>Can anyone tell me whats I am doing wrong because I am getting an API error? somehow I am not able to get the correct data that's why the database is also not filling up</p>
  
  <p>my <strong>GithubAPi</strong> response class is this  </p>
  
  <pre><code>public class GithubApiResponse {
  
      public GithubApiResponse() {
          this.items = new ArrayList&lt;&gt;();
      }
  
      public GithubApiResponse(List&lt;GithubEntity&gt; items) {
          this.items = items;
      }
  
      private List&lt;GithubEntity&gt; items;
  
  
      public List&lt;GithubEntity&gt; getItems() {
          return items;
      }
  
      public void setItems(List&lt;GithubEntity&gt; items) {
          this.items = items;
      }
  }
  </code></pre>
  
  <p>and the <strong>Entity</strong> class is this </p>
  
  <pre><code>@Entity
  public class GithubEntity implements Parcelable {
  
      public GithubEntity(@NonNull Long id, String author, String name, String avatar,
                          String url, String description, Integer stars, Integer forks, Integer currentPeriodStars, String language, String languageColor) {
          this.id = id;
          this.author = author;
          this.name = name;
          this.avatar = avatar;
          this.url = url;
          this.description = description;
          this.stars = stars;
          this.forks = forks;
          this.currentPeriodStars = currentPeriodStars;
          this.language = language;
          this.languageColor = languageColor;
      }
  
      @NonNull
      @PrimaryKey
      private Long id;
  
      @SerializedName("author")
      @Expose
      private String author;
      @SerializedName("name")
      @Expose
      private String name;
      @SerializedName("avatar")
      @Expose
      private String avatar;
      @SerializedName("url")
      @Expose
      private String url;
      @SerializedName("description")
      @Expose
      private String description;
      @SerializedName("stars")
      @Expose
      private Integer stars;
      @SerializedName("forks")
      @Expose
      private Integer forks;
      @SerializedName("currentPeriodStars")
      @Expose
      private Integer currentPeriodStars;
  
      @SerializedName("language")
      @Expose
      private String language;
      @SerializedName("languageColor")
      @Expose
      private String languageColor;
  
      @NonNull
      public Long getId() {
          return id;
      }
  
      public void setId(@NonNull Long id) {
          this.id = id;
      }
  
      protected GithubEntity(Parcel in) {
          author = in.readString();
          name = in.readString();
          avatar = in.readString();
          url = in.readString();
          description = in.readString();
          if (in.readByte() == 0) {
              stars = null;
          } else {
              stars = in.readInt();
          }
          if (in.readByte() == 0) {
              forks = null;
          } else {
              forks = in.readInt();
          }
          if (in.readByte() == 0) {
              currentPeriodStars = null;
          } else {
              currentPeriodStars = in.readInt();
          }
          language = in.readString();
          languageColor = in.readString();
      }
  
      public static final Creator&lt;GithubEntity&gt; CREATOR = new Creator&lt;GithubEntity&gt;() {
          @Override
          public GithubEntity createFromParcel(Parcel in) {
              return new GithubEntity(in);
          }
  
          @Override
          public GithubEntity[] newArray(int size) {
              return new GithubEntity[size];
          }
      };
  
      public String getAuthor() {
          return author;
      }
  
      public void setAuthor(String author) {
          this.author = author;
      }
  
      public String getName() {
          return name;
      }
  
      public void setName(String name) {
          this.name = name;
      }
  
      public String getAvatar() {
          return avatar;
      }
  
      public void setAvatar(String avatar) {
          this.avatar = avatar;
      }
  
      public String getUrl() {
          return url;
      }
  
      public void setUrl(String url) {
          this.url = url;
      }
  
      public String getDescription() {
          return description;
      }
  
      public void setDescription(String description) {
          this.description = description;
      }
  
      public Integer getStars() {
          return stars;
      }
  
      public void setStars(Integer stars) {
          this.stars = stars;
      }
  
      public Integer getForks() {
          return forks;
      }
  
      public void setForks(Integer forks) {
          this.forks = forks;
      }
  
      public Integer getCurrentPeriodStars() {
          return currentPeriodStars;
      }
  
      public void setCurrentPeriodStars(Integer currentPeriodStars) {
          this.currentPeriodStars = currentPeriodStars;
      }
  
  
      public String getLanguage() {
          return language;
      }
  
      public void setLanguage(String language) {
          this.language = language;
      }
  
      public String getLanguageColor() {
          return languageColor;
      }
  
      public void setLanguageColor(String languageColor) {
          this.languageColor = languageColor;
      }
  
  
      @Override
      public int describeContents() {
          return 0;
      }
  
      @Override
      public void writeToParcel(Parcel dest, int flags) {
          dest.writeString(author);
          dest.writeString(name);
          dest.writeString(avatar);
          dest.writeString(url);
          dest.writeString(description);
          if (stars == null) {
              dest.writeByte((byte) 0);
          } else {
              dest.writeByte((byte) 1);
              dest.writeInt(stars);
          }
          if (forks == null) {
              dest.writeByte((byte) 0);
          } else {
              dest.writeByte((byte) 1);
              dest.writeInt(forks);
          }
          if (currentPeriodStars == null) {
              dest.writeByte((byte) 0);
          } else {
              dest.writeByte((byte) 1);
              dest.writeInt(currentPeriodStars);
          }
          dest.writeString(language);
          dest.writeString(languageColor);
      }
  }
  </code></pre>
  
  <p>can anyone guide me so that I can fix this issue? stuck here for 2 days </p>