skip to Main Content

I am using retrofit2.6.2 for api call. LoggingInterceptor showing full response in logcat but retrofit response body return null. I didn’t figure out where is my problem.

My json data schema is

{
   "error":false,
   "msg":"Banner Found",
   "id":"9",
   "activity":"VipPremium1",
   "imageUrl":"https://1.bp.blogspot.com/-Kh3RQlJH7Xw/X-1mIPi7_HI/AAAAAAAAFME/Y2bCnU5odngcdDT83uC9QwUr7IGJdTDfACLcBGAsYHQ/s2616/COMPRESSED_IMG_1609393684674.jpg",
   "actionUrl":"https://www.youtube.com/watch?v=ukJX5ZgJec4",
   "actionType":1,
   "visible":true
}

Model Class BannerRes

data class BannerRes(
    @SerializedName("actionType")
    val actionType: Int?,
    @SerializedName("actionUrl")
    val actionUrl: String?,
    @SerializedName("activity")
    val activity: String?,
    @SerializedName("error")
    val error: Boolean?,
    @SerializedName("id")
    val id: String?,
    @SerializedName("imageUrl")
    val imageUrl: String?,
    @SerializedName("msg")
    val msg: String?,
    @SerializedName("visible")
    val visible: Boolean?
)

Api Interface

@GET("api/helper.getBanner.php")
    suspend fun getBanner(
        @Query("bannerName") bannerName: String,
    ): Response<BannerRes>

Api call done here

private fun loadPremiumBanner() {
       
        Coroutines.main {
           val res =  viewModel.getBanner("VipPremium1")
            Log.d("Response", res.body()!!.msg!!) 
        }
    }

When I print response body using

 Log.d("Response", Gson().toJson(res.body()))

It shows the the response in logcat,
Logcat

{"error":false,"msg":"Banner Found","id":"9","activity":"VipPremium1","imageUrl":"https://1.bp.blogspot.com/-Kh3RQlJH7Xw/X-1mIPi7_HI/AAAAAAAAFME/Y2bCnU5odngcdDT83uC9QwUr7IGJdTDfACLcBGAsYHQ/s2616/COMPRESSED_IMG_1609393684674.jpg","actionUrl":"https://www.youtube.com/watch?vu003dukJX5ZgJec4","actionType":1.0,"visible":true}

but when access res.body()!!.msg It shows null.

Retrofit Setup

companion object {

        @Volatile
        private var myApiInstance: MyApi? = null
        private val LOCK = Any()

        operator fun invoke() = myApiInstance ?: synchronized(LOCK) {
            myApiInstance ?: createClient().also {
                myApiInstance = it
            }
        }

        private fun createClient(): MyApi {
            val AUTH: String = "Basic ${
                Base64.encodeToString(
                    ("${BuildConfig.USER_NAME}:${BuildConfig.USER_PASSWORD}").toByteArray(),
                    Base64.NO_WRAP
                )
            }"



            val interceptor = run {
                val httpLoggingInterceptor = HttpLoggingInterceptor()
                httpLoggingInterceptor.apply {
                    httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
                }
            }


            val okHttpClient: OkHttpClient = OkHttpClient.Builder()
                .callTimeout(10,TimeUnit.SECONDS)
                .addInterceptor(interceptor)
                .addInterceptor { chain ->
                    val original: Request = chain.request()
                    val requestBuilder: Request.Builder = original.newBuilder()
                        .addHeader("Authorization", AUTH)
                        .method(original.method, original.body)
                    val request: Request = requestBuilder.build()
                    chain.proceed(request)
                }
                .build()

            val gsonBuilder = GsonBuilder()
            gsonBuilder.setLenient()
            val gson = gsonBuilder.create()

            return Retrofit.Builder()
                .baseUrl(BuildConfig.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addConverterFactory(ScalarsConverterFactory.create())
                .client(okHttpClient)
                .build()
                .create(MyApi::class.java)
        }


    }

3

Answers


  1. Chosen as BEST ANSWER

    I resolved this issue by adding kotlin model data class member filed default value. I don't know what is the reason behind this,

    Old data class

    data class BannerRes(
        @SerializedName("actionType")
        val actionType: Int?,
        @SerializedName("actionUrl")
        val actionUrl: String?,
        @SerializedName("activity")
        val activity: String?,
        @SerializedName("error")
        val error: Boolean?,
        @SerializedName("id")
        val id: String?,
        @SerializedName("imageUrl")
        val imageUrl: String?,
        @SerializedName("msg")
        val msg: String?,
        @SerializedName("visible")
        val visible: Boolean?
    )
    

    Modified or data class with member field default value which fix my problem

    data class BannerRes(
        @SerializedName("error") var error : Boolean = true,
        @SerializedName("msg") var msg : String? = null,
        @SerializedName("id") var id : String? = null,
        @SerializedName("activity") var activity : String? = null,
        @SerializedName("imageUrl") var imageUrl : String? = null,
        @SerializedName("actionUrl") var actionUrl : String? = null,
        @SerializedName("actionType") var actionType : Int = 0,
        @SerializedName("visible") var visible : Boolean = false
        )
    

  2. I think you can’t use both Gson and Scalars Converter in Retrofit because retrofit confuse to wrap it.
    Remove Scaler (I prefer Gson) and try again.
    If not work then use GsonConverterFactory.create() this.

    Login or Signup to reply.
  3. With Retrofit you can consume the response body only once. So the first call to body() will return the response but further calls will not. You’re consuming your body when you’re logging it.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search