Making A Generic Network Adapter Using Livedata, Retrofit, Mvvm And Repository Pattern
I am new to android architecture components and I am trying to use LiveData and ViewModels with mvvm, repository pattern and retrofit. Referred to GitHubSample google gave in its a
Solution 1:
We can connect Activity/Fragment and ViewModel as below:
Firstly, we have to create our ApiResource which will handle the retrofit response.
publicclassApiResource<T> {
@NonNullprivate final Status status;
@Nullableprivate final T data;
@Nullableprivate final ErrorResponse errorResponse;
@Nullableprivate final String errorMessage;
privateApiResource(Status status, @Nullable T data, @NullableErrorResponse errorResponse, @NullableString errorMessage) {
this.status = status;
this.data = data;
this.errorResponse = errorResponse;
this.errorMessage = errorMessage;
}
publicstatic <T> ApiResource<T> create(Response<T> response) {
if (!response.isSuccessful()) {
try {
JSONObject jsonObject = newJSONObject(response.errorBody().string());
ErrorResponse errorResponse = newGson()
.fromJson(jsonObject.toString(), ErrorResponse.class);
returnnewApiResource<>(Status.ERROR, null, errorResponse, "Something went wrong.");
} catch (IOException | JSONException e) {
returnnewApiResource<>(Status.ERROR, null, null, "Response Unreachable");
}
}
returnnewApiResource<>(Status.SUCCESS, response.body(), null, null);
}
publicstatic <T> ApiResource<T> failure(String error) {
returnnewApiResource<>(Status.ERROR, null, null, error);
}
publicstatic <T> ApiResource<T> loading() {
returnnewApiResource<>(Status.LOADING, null, null, null);
}
@NonNullpublicStatusgetStatus() {
return status;
}
@Nullablepublic T getData() {
return data;
}
@NullablepublicErrorResponsegetErrorResponse() {
return errorResponse;
}
@NullablepublicStringgetErrorMessage() {
return errorMessage;
}
}
The Status is just an Enum class
as below:
publicenumStatus {
SUCCESS, ERROR, LOADING
}
The ErrorResponse class must be created in such a way that the getter and setter can handle the error.
RetrofitLiveData class
publicclassRetrofitLiveData<T> extendsLiveData<ApiResource<T>> {
privateCall<T> call;
publicRetrofitLiveData(Call<T> call) {
this.call = call;
setValue(ApiResource.loading());
}
Callback<T> callback = newCallback<T>() {
@OverridepublicvoidonResponse(Call<T> call, Response<T> response) {
setValue(ApiResource.create(response));
}
@OverridepublicvoidonFailure(Call<T> call, Throwable t) {
setValue(ApiResource.failure(t.getMessage()));
}
};
@OverrideprotectedvoidonActive() {
super.onActive();
call.enqueue(callback);
}
@OverrideprotectedvoidonInactive() {
super.onInactive();
if (!hasActiveObservers()) {
if (!call.isCanceled()) {
call.cancel();
}
}
}
}
Repository class
publicclassRepository {
publicLiveData<ApiResource<JunoBalanceResponse>> getJunoBalanceResponse(Map<String, String> headers) {
returnnewRetrofitLiveData<>(ApiClient.getJunoApi(ApiClient.BASE_URL.BASE).getJunoBalance(headers));
}
}
JunoBalanceResponse
contains the objects and its getters and setters that I am waiting as a response of my retrofit request.
below is an example for the api interface.
publicinterfaceJunoApi {
@Headers({"X-API-Version: 2"})
@GET("balance")
Call<JunoBalanceResponse> getJunoBalance(@HeaderMap Map<String, String> headers);
}
ApiClient class
publicclassApiClient{
publicenumBASE_URL{
AUTH, BASE
}
privatestatic Retrofit retrofit;
privatestaticfinalString JUNO_SANDBOX_AUTH_URL = "https://sandbox.boletobancario.com/authorization-server/";
privatestaticfinalString JUNO_SANDBOX_BASE_URL = "https://sandbox.boletobancario.com/api-integration/";
privatestatic Retrofit getRetrofit(String baseUrl) {
OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
.connectTimeout(90, TimeUnit.SECONDS)
.readTimeout(90, TimeUnit.SECONDS)
.writeTimeout(90, TimeUnit.SECONDS)
.build();
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit;
}
publicstatic JunoApi getJunoApi(BASE_URL targetPath) {
switch (targetPath) {
case AUTH: return getRetrofit(JUNO_SANDBOX_AUTH_URL).create(JunoApi.class);
case BASE: return getRetrofit(JUNO_SANDBOX_BASE_URL).create(JunoApi.class);
default: return getRetrofit(JUNO_SANDBOX_BASE_URL).create(JunoApi.class);
}
}
}
Now we can connect our Repository and ApiViewModel.
publicclassApiViewModelextendsViewModel {
privateRepository repository = newRepository();
publicLiveData<ApiResource<JunoBalanceResponse>> getJunoBalanceResponse(Map<String, String> headers) {
return repository.getJunoBalanceResponse(headers);
}
}
And finally, we can observe the retrofit response in our Activity/Fragment
apiViewModel = ViewModelProviders.of(requireActivity()).get(ApiViewModel.class);
apiViewModel.getJunoBalanceResponse(headers).observe(getViewLifecycleOwner(), new Observer<ApiResource<JunoBalanceResponse>>() {
@Override
publicvoidonChanged(ApiResource<JunoBalanceResponse> response) {
switch (response.getStatus()) {
case LOADING:
Log.i(TAG, "onChanged: BALANCE LOADING");
break;
case SUCCESS:
Log.i(TAG, "onChanged: BALANCE SUCCESS");
break;
case ERROR:
Log.i(TAG, "onChanged: BALANCE ERROR");
break;
}
}
});
Post a Comment for "Making A Generic Network Adapter Using Livedata, Retrofit, Mvvm And Repository Pattern"