#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. Я использую ваш метод получения статуса, спасибо. Но я действительно хочу закрыть «сопрограмму», когда сеть не подключена, что я могу сделать?