Handling socketTimeOutException using Call.enqueue on Android Studio(Kotlin)

43 Views Asked by At

My understanding of Call.Enqueue is that the OnFailure method is supposed to handle all failed responses including OnSocketTimeOutException, however that doesn't seem to be the case for me.

The code below helps to call data from the NewsApi services as well as adding an interceptor to track requests/response status. I added .connectTimeout(10,TimeUnit.MILLISECONDS).readTimeout(10,TimeUnit.MILLISECONDS) to test how my app will react in an event of a OnSocketTimeOutException

object RetrofitHelper {

private const val BASE_URL = "https://newsapi.org/v2/"

private fun httpclient(): OkHttpClient {
    val builder = OkHttpClient.Builder().connectTimeout(10,TimeUnit.MILLISECONDS).readTimeout(10,TimeUnit.MILLISECONDS)

    builder.addInterceptor(HttpLoggingInterceptor().apply {
        setLevel(HttpLoggingInterceptor.Level.BODY)



        builder.addInterceptor(
            ChuckerInterceptor.Builder(application_class.context)
                .collector(ChuckerCollector(application_class.context))
                .maxContentLength(250000L)
                .redactHeaders(emptySet())
                .alwaysReadResponseBody(false)
                .build()
        )
    })
    return builder.build()
}

fun getInstance(): Retrofit {

    return Retrofit.Builder()
        .client(httpclient())
        .baseUrl(BASE_URL)
        .addConverterFactory(MoshiConverterFactory.create())
        .build()
}

object NewsApiCall {
    val api by lazy {
        RetrofitHelper.getInstance().create(NewsApi::class.java)
    }
}
}

The code below belongs to my Repository where the logic of determining whether a response is a success, error or failure. The api key provided below is not the real API key, I edited it. I suspect that the error has something to do with the OnFailure method.

    fun getNewsCall(country: String, Category: String?): MutableLiveData<MutableList<Article>> {
    val call = RetrofitHelper.NewsApiCall.api.getNews(
        country,
        Category,
        "0169333ed3074dccbacd369ae6a3c4"
    )
    var Newlist = MutableLiveData<MutableList<Article>>()

    call.enqueue(object : Callback<NewsDataFromJson> {

        override fun onResponse(
            call: Call<NewsDataFromJson>,
            response: Response<NewsDataFromJson>
        ) {

            if (response.isSuccessful) {
                val body = response.body()
                if (body != null) {
                    Newlist.value = body.articles
                }
            } else {
                val jsonObj: JSONObject?
                    jsonObj = response.errorBody()?.string().let { JSONObject(it) }
                    if (jsonObj != null) {
                        MainActivity.apiRequestError = true
                        MainActivity.errorMessage = jsonObj.getString("message")
                        Newlist.value = mutableListOf<Article>()//
                    }
            }
        }

        override fun onFailure(call: Call<NewsDataFromJson>, t: Throwable) {
            MainActivity.apiRequestError = true
            MainActivity.errorMessage = t.localizedMessage as String
            Log.d("err_msg", "msg" + t.localizedMessage)
        }

    })
    return Newlist
}

The final part is the MainActivity, this is where I display the responses, if it is a success It will show the news articles, if it is an error or a failure, an error message is supposed to show up

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
    lifecycleScope.launch(Dispatchers.Main) {
        requestNews(GENERAL, generalNews, "us")
        requestNews(TECHNOLOGY, TechNews, "us")
        requestNews(HEALTH, healthNews, "us")
        requestNews(SPORTS, SportsNews, "us")
        requestNews(ENTERTAINMENT, EntertainmentNews, "us")
        requestNews(SCIENCE, ScienceNews, "us")
        requestNews(BUSINESS, BusinessNews, "us")
    }

}
suspend private fun requestNews(newsCategory: String, newsData: MutableList<Article>,country:String) {
    viewModel.getNews(category = newsCategory, Country = country)?.observe(this) {
        newsData.addAll(it)
        totalRequestCount += 1

        lifecycleScope.launch(Dispatchers.Main) {


    if (ScienceNews.isNotEmpty() && BusinessNews.isNotEmpty() && EntertainmentNews.isNotEmpty() && generalNews.isNotEmpty() && healthNews.isNotEmpty() && SportsNews.isNotEmpty() && TechNews.isNotEmpty()) {
        if (apiRequestError == false) {
            ProgresBar.visibility = View.GONE
            FragmentContainer.visibility = View.VISIBLE

        } else if (apiRequestError == true) {
            ProgresBar.visibility = View.GONE
            FragmentContainer.visibility = View.GONE
            val showError: TextView = findViewById(R.id.display_error)
            showError.text = errorMessage
            showError.visibility = View.VISIBLE
        }

    } else if (apiRequestError == true) {
        ProgresBar.visibility = View.GONE
        FragmentContainer.visibility = View.GONE
        val showError: TextView = findViewById(R.id.display_error)
        showError.text = errorMessage
        showError.visibility = View.VISIBLE
    }

        }
    }
}
companion object{
    //var generalNews changed from ArrayList<NewsModel>
    var ScienceNews: MutableList<Article> = mutableListOf()
    var EntertainmentNews: MutableList<Article> = mutableListOf()
    var SportsNews: MutableList<Article> = mutableListOf()
    var BusinessNews: MutableList<Article> = mutableListOf()
    var healthNews: MutableList<Article> = mutableListOf()
    var generalNews: MutableList<Article> = mutableListOf()
    var TechNews: MutableList<Article> = mutableListOf()
    var apiRequestError = false
    var errorMessage = "error"

}

}

When I run the app this is what I see, the loading screen is not disappearing which is weird, which leads me to believe that the error may lie with the OnFailure method in the Repository.

Error Image

Error Response

0

There are 0 best solutions below