Привет, я только начал работать с mvvm с шаблоном репозитория. Я застрял с ошибкой API. Я использую обобщенный класс c API Response согласно официальному репозиторию Google в java
/**
* Generic class for handling responses from Retrofit
*
* @param <T>
*/
public class ApiResponse<T> {
public ApiResponse<T> create(Throwable error) {
return new ApiErrorResponse<>(error.getMessage().equals("") ? error.getMessage() : "Unknown error\nCheck network connection");
}
public ApiResponse<T> create(Response<T> response) {
if (response.isSuccessful()) {
T body = response.body();
if (body instanceof GithubApiResponse) {
if (AppUtils.isValid((GithubApiResponse) body)) {
String errorMsg = "Empty Response.";
return new ApiErrorResponse<>(errorMsg);
}
}
if (body == null || response.code() == 204) { // 204 is empty response
return new ApiEmptyResponse<>();
} else {
return new ApiSuccessResponse<>(body);
}
} else {
String errorMsg = "";
try {
errorMsg = response.errorBody().string();
} catch (IOException e) {
e.printStackTrace();
errorMsg = response.message();
}
return new ApiErrorResponse<>(errorMsg);
}
}
/**
* Generic success response from api
*
* @param <T>
*/
public class ApiSuccessResponse<T> extends ApiResponse<T> {
private T body;
ApiSuccessResponse(T body) {
this.body = body;
}
public T getBody() {
return body;
}
}
/**
* Generic Error response from API
*
* @param <T>
*/
public class ApiErrorResponse<T> extends ApiResponse<T> {
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<T> extends ApiResponse<T> {
}
}
и Мой networkBoundResource как этот
public abstract class NetworkBoundResource<ResultType, RequestType> {
private AppExecutors appExecutors;
private MediatorLiveData<Resource<ResultType>> results = new MediatorLiveData<>();
public NetworkBoundResource(AppExecutors appExecutors) {
this.appExecutors = appExecutors;
init();
}
private void init() {
// update LiveData for loading status
results.setValue((Resource<ResultType>) Resource.loading(null));
// observe LiveData source from local db
final LiveData<ResultType> dbSource = loadFromDb();
results.addSource(dbSource, new Observer<ResultType>() {
@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<ResultType>() {
@Override
public void onChanged(@Nullable ResultType ResultType) {
setValue(Resource.success(ResultType));
}
});
}
}
});
}
/**
* 1) observe local db
* 2) if <condition/> 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<ResultType> dbSource) {
Timber.d("fetchFromNetwork: called.");
// update LiveData for loading status
results.addSource(dbSource, new Observer<ResultType>() {
@Override
public void onChanged(@Nullable ResultType ResultType) {
setValue(Resource.loading(ResultType));
}
});
final LiveData<ApiResponse<RequestType>> apiResponse = createCall();
results.addSource(apiResponse, new Observer<ApiResponse<RequestType>>() {
@Override
public void onChanged(@Nullable final ApiResponse<RequestType> 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<ResultType>() {
@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<ResultType>() {
@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<ResultType>() {
@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<ResultType> 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<ResultType> loadFromDb();
// Called to create the API call.
@NonNull
@MainThread
protected abstract LiveData<ApiResponse<RequestType>> createCall();
// Returns a LiveData object that represents the resource that's implemented
// in the base class.
public final LiveData<Resource<ResultType>> getAsLiveData() {
return results;
}
}
мой репозиторий выглядит так
@Singleton
public class GithubRepository {
private GithubDao githubDao;
private GithubTrendingApiService githubApiService;
public GithubRepository(GithubDao githubDao, GithubTrendingApiService githubApiService) {
this.githubDao = githubDao;
this.githubApiService = githubApiService;
}
public LiveData<Resource<List<GithubEntity>>> getRepositories() {
return new NetworkBoundResource<List<GithubEntity>, GithubApiResponse>(AppExecutors.getInstance()) {
@Override
protected void saveCallResult(@NonNull GithubApiResponse item) {
List<GithubEntity> repositories = item.getItems();
githubDao.insertRepositories(repositories);
}
@Override
protected boolean shouldFetch(@Nullable List<GithubEntity> 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()) >= 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<List<GithubEntity>> loadFromDb() {
return githubDao.getTrendingRepository();
}
@NonNull
@Override
protected LiveData<ApiResponse<GithubApiResponse>> createCall() {
return githubApiService.fetchTrendingRepositories();
}
}.getAsLiveData();
}
}
Может кто-нибудь сказать мне, что я делаю неправильно, потому что Я получаю ошибку API? почему-то я не могу получить правильные данные, поэтому база данных также не заполняет
мой GithubAPi класс ответа это
public class GithubApiResponse {
public GithubApiResponse() {
this.items = new ArrayList<>();
}
public GithubApiResponse(List<GithubEntity> items) {
this.items = items;
}
private List<GithubEntity> items;
public List<GithubEntity> getItems() {
return items;
}
public void setItems(List<GithubEntity> items) {
this.items = items;
}
}
и Entity класс это
@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<GithubEntity> CREATOR = new Creator<GithubEntity>() {
@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);
}
}
Может кто-нибудь направить меня, чтобы я мог решить эту проблему? застрял здесь на 2 дня