Skip to content Skip to sidebar Skip to footer

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"