简体   繁体   中英

How to wrap retrofit response with generic response

I am following after "Google Best Practices" and they suggested to add Generic response handler.

I added This generic response handler, I wrap my model with the response handler, but I've really hard time to understand how can I use this.

For my understanding, I need to call to create method, and pass response or error and this class handles all the rest, and return if it was empty/sucess/error.

Where am I calling this create method?

This is currently my approach, and obviously it's now working( getting Failed to invoke private com.example.resclassex.utils.GenericApiResponse() with no args error)

This is the generic class:

sealed class GenericApiResponse<T> {

    companion object {
        private val TAG: String = "AppDebug"


        fun <T> create(error: Throwable): ApiErrorResponse<T> {
            return ApiErrorResponse(error.message ?: "unknown error")
        }

        fun <T> create(response: Response<T>): GenericApiResponse<T> {

            if(response.isSuccessful){
                val body = response.body()
                if (body == null || response.code() == 204) {
                    return ApiEmptyResponse()
                }
                else if(response.code() == 401){
                    return ApiErrorResponse("401 Unauthorized. Token may be invalid.")
                }
                else {
                    return ApiSuccessResponse(body = body)
                }
            }
            else{
                val msg = response.errorBody()?.string()
                val errorMsg = if (msg.isNullOrEmpty()) {
                    response.message()
                } else {
                    msg
                }
                return ApiErrorResponse(errorMsg ?: "unknown error")
            }
        }
    }
}

class ApiEmptyResponse<T> : GenericApiResponse<T>()

data class ApiSuccessResponse<T>(val body: T) : GenericApiResponse<T>() {}

data class ApiErrorResponse<T>(val errorMessage: String) : GenericApiResponse<T>()

call enque:

    private fun getMovies() {
    val call = RetrofitService.moviesApiService.getAllMovies(Constants.API_KEY)

    call.enqueue(object : Callback<GenericApiResponse<AllMovies>> {
        override fun onResponse(
            call: Call<GenericApiResponse<AllMovies>>,
            response: Response<GenericApiResponse<AllMovies>>
        ) {
            Log.d(TAG, "onResponse: ")
        }

        override fun onFailure(call: Call<GenericApiResponse<AllMovies>>, t: Throwable) {
            Log.d(TAG, "onFailure: $t")
        }
    })
}

I also encountered the same problem, but the issue with mine implementation was that coroutines and suspend function CallAdapter was unable to convert response into liveData wrapper around GenericResponse<NetworkResponse> .

I removed the suspend function and I no longer I got Failed to invoke private com.example.resclassex.utils.GenericApiResponse() with no args.

You can share the API interface's return type.

You can also debug the callAdapterFactory if correct adapter is returned by factory.

I built a base structure that followed Google's recommendation. You can check it here: (branch: sample)

https://github.com/frank-nhatvm/fatherofapps

Take note that: sample branch. In this source code, you can find how to define genetic class and how to use it with network layer. And how to call it in VIewModel, Repository, Service

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM