Home » Android » android – Throwing IOException in Interceptor is causing the crash with Retrofit-Exceptionshub

android – Throwing IOException in Interceptor is causing the crash with Retrofit-Exceptionshub

Posted by: admin February 26, 2020 Leave a comment

Questions:

I am trying to handle the exceptions due to the server and client network connections.
I have made an Interceptor class for handling those errors globally as the square docs.
Every time I tried to execute the network calls without a network connection, this error kicked in and causing my app to crash.

Edited : If the connection is too slow enough to trigger SocketTimeOutExeception , it also caused the app to crash. I have tried to cover it with a way in which the network calls will only be executed if there is an active network connection. But like I said before, the connection is too slow , the error kicked in the same with SocketTimeOutExeception. The app works well with a good, active network connection

W/System.err: java.net.UnknownHostException: Unable to resolve host "0725394a.ngrok.io": No address associated with hostname
        at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:157)
        at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:105)
        at java.net.InetAddress.getAllByName(InetAddress.java:1154)
W/System.err:     at okhttp3.Dns$Companion$DnsSystem.lookup(Dns.kt:49)
        at okhttp3.internal.connection.RouteSelector.resetNextInetSocketAddress(RouteSelector.kt:164)
        at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.kt:129)
        at okhttp3.internal.connection.RouteSelector.next(RouteSelector.kt:71)
        at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:197)
        at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:107)
        at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:75)
        at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:245)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:82)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:74)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
        at com.network.di.AuthenticationInterceptor.intercept(AuthenticationInterceptor.kt:63)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
        at com.network.exception.NetworkExceptionInterceptor.intercept(NetworkExceptionInterceptor.kt:11)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
        at com.readystatesoftware.chuck.ChuckInterceptor.intercept(ChuckInterceptor.java:172)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
        at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.kt:219)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
        at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:197)
        at okhttp3.internal.connection.RealCall.execute(RealCall.kt:148)
        at retrofit2.OkHttpCall.execute(OkHttpCall.java:188)
        at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall.execute(DefaultCallAdapterFactory.java:97)
W/System.err:     at com.network.datasource.CourseDetailsDataSourcecImpl.getChaptersByPagination(CourseDetailsDataSourcecImpl.kt:39)
        at com.data.repository.CourseDetailsRepositoryImpl.getChapterList(CourseDetailsRepositoryImpl.kt:19)
        at com.domain.interactors.coursedetails.GetCourseChaptersByPagination$provideObservable$1.call(GetCourseChaptersByPagination.kt:26)
        at com.domain.interactors.coursedetails.GetCourseChaptersByPagination$provideObservable$1.call(GetCourseChaptersByPagination.kt:11)
        at io.reactivex.internal.operators.observable.ObservableFromCallable.subscribeActual(ObservableFromCallable.java:43)
        at io.reactivex.Observable.subscribe(Observable.java:12246)
        at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
        at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker$BooleanRunnable.run(ExecutorScheduler.java:288)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)

This is the error I’ve been getting.

This are my interceptor classes

class AuthenticationInterceptor() : Interceptor {
    private var bearerToken : String? = ""
    private var token : String? = ""
    private var customToken : String? = null
    private var customTag : String? = null
    private var onlyUseCustomHeader : Boolean = false

    private var customName : String? = null


    fun setCustom(customName : String? , customTag : String? , customToken : String?) {
        this.customToken = customToken
        this.customTag = customTag
        this.customName = customName
    }


    fun setOnlyUseCustomHeader(onlyUseCustomHeader : Boolean) {
        this.onlyUseCustomHeader = onlyUseCustomHeader
    }


    constructor(
        bearerToken : String?,
        token : String?
    ) : this() {
        this.bearerToken = bearerToken
        this.token = token
    }

    @Throws(IOException::class)
    override fun intercept(chain : Interceptor.Chain) : Response {
        val builder = chain.request().newBuilder()
        if (!onlyUseCustomHeader) {
            if (customName != null && customToken != null) {
                if (customTag == null)
                    builder.addHeader("$customName" , "$customToken")
                else
                    builder.addHeader("$customName" , "$customTag $customToken")
            }

            if (bearerToken != null && bearerToken != "")
                builder.addHeader("Authorization" , "Bearer $bearerToken")
            if (token != null && token != "")
                builder.addHeader("token" , "$token")
        } else {
            if (customName != null && customToken != null) {
                if (customTag == null)
                    builder.addHeader("$customName" , "$customToken")
                else
                    builder.addHeader("$customName" , "$customTag $customToken")
            }
        }
        builder.addHeader("Accept" , "application/json")

        val request = builder.build()
        return chain.proceed(request)
    }

}

class NetworkExceptionInterceptor : Interceptor {
    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {

        val response = chain.proceed(chain.request())
        when (response.isSuccessful) {
            true  -> return response
            false -> {
                throw NetworkException(response.body , response.code)
            }
        }

    }
}

And this is my custom error class.

data class NetworkException constructor(
    var errorBody: ResponseBody? = null,
    var errorCode: Int
) : IOException() 

These are the methods for providing OkhttpClient and Retrofit.Builder() where I added the Network Interceptor and the Authenticating interceptor.

        @Provides
        fun providesOkHttpClientBuilder(context : Context) : OkHttpClient.Builder {

            return OkHttpClient.Builder().apply {

                val loggerInterceptor = HttpLoggingInterceptor().apply {
                    level = when (BuildConfig.DEBUG) {
                        true  -> HttpLoggingInterceptor.Level.HEADERS
                        false -> HttpLoggingInterceptor.Level.NONE
                    }
                }

                addInterceptor(loggerInterceptor)
                      .addInterceptor(ChuckInterceptor(context))
                    .addInterceptor(NetworkExceptionInterceptor())
                    .readTimeout(8 , TimeUnit.SECONDS)
                    .writeTimeout(8 , TimeUnit.SECONDS)
                    .connectTimeout(8 , TimeUnit.SECONDS)
                    .cache(null)
            }
        }

   @JvmStatic
        @NonNull
        @Named("authenticatedBuilder")
        @Provides
        fun getAuthenticatedBuilder(@Named("bearer_token") bearerToken : String? , @Named("token") token : String? , httpClientBuilder : OkHttpClient.Builder ,@Named("primary") retrofitBuilder : Retrofit.Builder) : Retrofit.Builder {
            showLogD("NETWORK_MODULE" , "BearerToken before interception : $bearerToken")
            showLogD("NETWORK_MODULE" , "TOKEN before interception : $token")
            val interceptor : Interceptor =
                AuthenticationInterceptor(bearerToken , token)
            if (!httpClientBuilder.interceptors().contains(interceptor)) {
                httpClientBuilder.addInterceptor(interceptor)
            }
            return retrofitBuilder.client(httpClientBuilder.build())

        }

Edited 2 : This is the CourseDetailsDataSourceImpl.kt

class CourseDetailsDataSourcecImpl @Inject constructor(
    private val courseDetailsService : CourseDetailsService ,
    private val courseDetailsMapper : CourseDetailsMapper ,
    private val chapterListMapper : CourseChapterListMapper ,
    private val lessonSnapShotMapper : LessonSnapShotMapper ,
    private val vdoPlayerOTPMapper : VdoPlayerOTPMapper
) : CourseDetailsDataSource {

    @Inject
    lateinit var vdoPlayerService : VdoPlayerService

    override fun getCourseDetails(courseID : String) : CourseDetailsVO {
        return courseDetailsMapper.map(courseDetailsService.getCourseDetails(courseID).execute().body()!!)
    }

    override fun getCourseVideoDetails(lessonID : String) : LessonSnapShotVO {
        return lessonSnapShotMapper.map(courseDetailsService.getLessonDetails(lessonID).execute().body()!!)
    }

    override fun getChaptersByPagination(courseID : String , pageNumber : Int) : CourseChapterListVO{
        //todo implement this with pagination
        return chapterListMapper.map(courseDetailsService.getCourseChapters(courseID).execute().body()!!)
    }

    override fun getVdoPlayerOtp(videoID : String) : VdoPlayerOTPResponseVO {
        return vdoPlayerOTPMapper.map(vdoPlayerService.getOtp( videoID , VDOOTPRequestBody()).execute().body()!!)
    }

}

Any idea how to resolve this?

How to&Answers: