Как сделать так, чтобы сеть не была подключена, а время ожидания подключения истекло при модернизации

#android #kotlin #retrofit

Вопрос:

Я хочу получить статус сетевого подключения с помощью дооснащения.

Я привык CoroutineExceptionHandler показывать Toast , но это получится Can't toast on a thread that has not called Looper.prepare() .

Если я не использую CoroutineExceptionHandler , когда сеть не подключена, она разбивается и получает FATAL EXCEPTION: DefaultDispatcher-worker-1 .

Как я могу получить статус «Сеть не подключена» и «время ожидания подключения истекло»?

Вот мой код, спасибо!

 object APIClientManager {
    var tag: String = "APIClientManager"

    fun postMethod(_jsonObject: JSONObject, _parameters: JSONObject) {
        getResult(_jsonObject, _parameters)
    }

    fun getResult(_jsonObject: JSONObject, _parameters: JSONObject) {
        // set okHttpClient.
        val httpClient = OkHttpClient.Builder()
        httpClient.addInterceptor { chain ->
            val original = chain.request()

            val requestBuilder = original.newBuilder()
            requestBuilder
                .header("Content-Type", "application/json; charset=UTF-8")

            val request = requestBuilder.build()
            chain.proceed(request)
        }

        httpClient.connectTimeout(30, TimeUnit.SECONDS)
        httpClient.readTimeout(30, TimeUnit.SECONDS)

        val okHttpClient = httpClient.build()

        // Create Retrofit
        val retrofit = Retrofit.Builder()
            .baseUrl(GbApiSite)
            .client(okHttpClient)
            .build()

        // Create Service
        val service = retrofit.create(APIService::class.java)

        // Convert JSONObject to String
        val jsonObjectString = _jsonObject.toString()

        // Create RequestBody
        val requestBody = jsonObjectString.toRequestBody("application/json".toMediaTypeOrNull())

        val exceptionHandler = CoroutineExceptionHandler{_ , throwable->
            throwable.printStackTrace()
            // I want to show toast here but will get "Can't toast on a thread that has not called Looper.prepare()".
        }

        CoroutineScope(Dispatchers.IO   exceptionHandler).launch {
            // Do the POST request and get response
            val response = APIServiceFun(_parameters, service, requestBody).chooseFun()

            withContext(Dispatchers.Main) {
                if (response != null) {
                    if (response.isSuccessful) {
                        val gson = GsonBuilder().serializeNulls().create()
                        val json = gson.toJson(
                            JsonParser.parseString(
                                response.body()?.
                                string()
                            )
                        )

                        var returnJSONObj = JSONObject(json)

                        if(returnJSONObj.has("return_code")){
                            var returnCode = returnJSONObj.getString("return_code")

                            if(returnCode.compareTo("0") == 0){
                                if(returnJSONObj.has("return_msg"))
                                    APIServiceResult(returnJSONObj.getJSONObject("return_msg"), _parameters).chooseActivity()
                            }
                        }
                    } else
                        Log.e("retrofit error ", response.code().toString())
                } else {
                    Log.e(tag, "response is null")
                }
            }
        }
    }

}
 

Ответ №1:

Вы всегда должны выполнять обработку исключений для любого IO связанного кода, так как вероятность его сбоя очень высока, это можно легко сделать, обернув ваш сетевой вызывающий код в try catch

 try{
    val response = APIServiceFun(_parameters, service, requestBody).chooseFun()
}
catch(e: SocketTimeoutException){
    Log.d("TAG", "Exception : $e")
}
catch(e: Exception){
    Log.d("TAG", "Exception : $e")
}
 

Чтобы показать ошибку в a Toast , вы можете использовать LiveData объект в своем APIClientManager и наблюдать его в своем Activity или Fragment

 /* In APIClientManager */
val apiError: MutableLiveData<String> = MutableLiveData()

// post error to this LiveData inside catch block as
try{}
catch(e: SocketTimeoutException){
    apiError.postValue("API call timed out, please try again")
}
catch(e: Exception){
    apiError.postValue("Network error occurred, please try again")
}

/* In Activity onCreate, observe the LiveData and show Toast when erro occurs */
APIClientmanager.apiError.observe(this, Observer{
    if(!it.isNullOrEmpty){
        Toast.makeText(requireContext, it, Toast.LENGTH_LONG).show()
    }
}
 

Комментарии:

1. Я использую ваш метод получения статуса, спасибо. Но я действительно хочу закрыть «сопрограмму», когда сеть не подключена, что я могу сделать?