使用Kotlin Coroutines处理翻新版2.6的互联网连接无错误

时间:2019-06-22 07:24:16

标签: android kotlin retrofit2 kotlin-coroutines

我正在使用带有Kotlin协程的Retrofit 2.6进行API调用,而不会阻塞UI线程,我可以正常工作,但是当我关闭Internet连接时,应用程序崩溃了。 logcat错误为:E / AndroidRuntime:致命异常:DefaultDispatcher-worker-1

这是我的代码:

private fun handleIntent(slug: String) {
    val service = UtilityMethods.migrationTimeService()

    UtilityMethods.showView(loading_view)
    UtilityMethods.hideView(network_error_msg)

    CoroutineScope(Dispatchers.IO).launch {
        val res = service.getPostBySlug(slug)

            try {
                withContext(Dispatchers.Main) {

                    //Do something with response e.g show to the UI.
                    val post = res.body()!!.first()

                    UtilityMethods.hideView(loading_view)

                    val title = post.title?.rendered
                    val content = post.content?.rendered
                    val imageUrl = post.jetPackFeaturedMediaUrl

                    title_txtView.text = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                        Html.fromHtml(title, Html.FROM_HTML_MODE_COMPACT).toString()
                    else
                        Html.fromHtml(title).toString()

                    content_txtView.loadData(content.toString(), "text/html", "UTF-8")

                    Picasso.get().load(imageUrl).fit().centerCrop().into(thumbnail_imgview)
                }

            } catch (e: HttpException) {
                UtilityMethods.showView(network_error_msg)
            } catch (e: Throwable) {
                Toast.makeText(this@PostContentActivity, "Ooops: Something else went wrong", Toast.LENGTH_LONG)
            }
    }
}

3 个答案:

答案 0 :(得分:0)

代替此:

    CoroutineScope(Dispatchers.IO).launch {
    val res = service.getPostBySlug(slug)

        try {
            withContext(Dispatchers.Main) {

尝试这个:

    CoroutineScope(Dispatchers.Main).launch {
    val res = service.getPostBySlug(slug)

        withContext(Dispatchers.IO) {
            try {

在Dispatchers.IO中包装“ try and catch”块代码,而不是在try try块中包装Dispatchers.IO

答案 1 :(得分:0)

我的代码已经生效,新的代码是:

private fun handleIntent(slug: String) = GlobalScope.launch(Dispatchers.Main) {
    val service = UtilityMethods.migrationTimeService()

    UtilityMethods.showView(loading_view)
    UtilityMethods.hideView(network_error_msg)

    try {
        val res = withContext(Dispatchers.IO) {
            service.getPostBySlug(slug)
        }

        //Do something with response e.g show to the UI.
        val post = res.body()!!.first()

        UtilityMethods.hideView(loading_view)

        val title = post.title?.rendered
        val content = post.content?.rendered
        val imageUrl = post.jetPackFeaturedMediaUrl

        title_txtView.text = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
            Html.fromHtml(title, Html.FROM_HTML_MODE_COMPACT).toString()
        else
            Html.fromHtml(title).toString()

        content_txtView.loadData(content.toString(), "text/html", "UTF-8")

        Picasso.get().load(imageUrl).fit().centerCrop().into(thumbnail_imgview)
    }
    catch (e: HttpException) {
        Toast.makeText(this@PostContentActivity, "Exception ${e.message}", Toast.LENGTH_LONG).show()
    }catch (e: IOException) {
        UtilityMethods.hideView(loading_view)
        UtilityMethods.showView(network_error_msg)
    } catch (e: Throwable) {
        Toast.makeText(this@PostContentActivity, "Ooops: Something else went wrong ${e.message}", Toast.LENGTH_LONG).show()
    }
}

答案 2 :(得分:0)

因此,在查看stacktrace时,我发现当网络不可用时会抛出ConnectException

这就是我在Kotlin中所做的事情,它对我有用,

suspend fun<T: Any> safeAPICall(call: suspend () -> Response<T>) : T{
val response = try {
    call.invoke()
}
catch (e:java.lang.Exception){
    e.printStackTrace()
    val message = if( e is ConnectException) "Connection Error" else "Something went wrong. Please try again."
    throw IOException(ResponseError(message, 500).convertToJsonString())
}


// When connection is OK

if(response.isSuccessful){
    return response.body()!!
}else{
    val error = response.errorBody()?.string()

    error?.let{
        val message = JSONObject(it).optString("message", "Something went wrong")
        val responseError = ResponseError(message, response.code())
        throw IOException(responseError.convertToJsonString())

    }
    throw IOException(ResponseError("Something went wrong. Please try again.", 500).convertToJsonString())
}
}

我使用的数据类

data class ResponseError(val message:String, val errorCode:Int)

用法:

try {
      val response = safeAPICall {APIClient.planner.viewSites(view.context.authToken)}
 }
 catch (e:Exception){
    view.snack(e.message?.toModel<ResponseError>()?.message?: unspecified_error)
 }

奖金:

 inline fun <reified T> JSONObject.toModel(): T? = this.run {
   try {
       Gson().fromJson<T>(this.toString(), T::class.java)
   }
   catch (e:java.lang.Exception){ e.printStackTrace(); null }
}


inline fun <reified T> String.toModel(): T? = this.run {
   try {
      JSONObject(this).toModel<T>()
    }
   catch (e:java.lang.Exception){  null }
}