改造中如何让网络未连接和连接超时

How to get network not connected and connection timed out in 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")
                }
            }
        }
    }

}

您应该始终对任何 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")
}

要在 Toast 中显示错误,您可以在 APIClientManager 中使用 LiveData 对象并在 ActivityFragment[ 中观察它=20=]

/* 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()
    }
}