• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

一步步基于ViewModel协程搭建通用网络请求工具

android 搞代码 3年前 (2022-05-09) 17次浏览 已收录 0个评论

本文次要介绍如何在ViewModel封装通用的网络申请,不过在真正介绍封装前先解说下应用到的基础知识:协程中异样的捕捉

1.协程中异样的捕捉

协程中异样捕捉的形式有两种:

  • 常见的try-catch

相比拟于CoroutineExceptionHandler,这种形式能够灵便的捕获可能产生异样的代码块:

lifecycleScope.launch {
    //省略其余逻辑代码
    try {
        val result = 8 / 0
    } catch (e: Exception) {
    }
    //省略其余逻辑代码
}
  • 协程上下文元素CoroutineExceptionHandler

这种形式捕获的异样是间接捕获的整个协程块的异样,颗粒度比拟大,短少灵活性。

lifecycleScope.launch(CoroutineExceptionHandler { _, throwable ->
    Log.e("ChapterActivity", "exception occur: ${throwable.message}")
}) {
    //省略其余逻辑代码
    val result = 8 / 0
    //省略其余逻辑代码
}

2.封装网络申请

首先定义一个类,类中别离定义三种函数类型属性,别离用作:发动申请、申请胜利、申请失败

class Action<T> {
    //发动申请
    var request: (suspend () -> Response<T>)? = null
        private set

    //申请胜利
    var success: ((T) -> Unit)? = null
        private set

    //申请失败
    var error: ((Throwable) -> Unit)? = null
        private set

    fun request(block: suspend () -> Response<T>) {
        request = block
    }

    fun success(block: (T) -> Unit) {
        success = block
    }

    fun error(block: (Throwable) -> Unit) {
        error = block
    }
}

data class Response<T>(val code: Int = -1, val data: T? = null)

定义一个扩大函数netRequest,以DSL的形式创立Action<T>对象:

fun <T> ViewModel.netRequest(block: Action<T>.() -> Unit) {
    val action = Action<T>().apply(block)
}

咱们就能够这样创立Action<T>对象并为其函数类型的属性别离设置值:

netRequest<String> { 
    request { 
        //模仿执行网络耗时
        delay(5* 1000)
        Response("dd")
    }
    success { 
        //申请胜利执行代码逻辑
    }
    error { 
        //申请失败执行的代码逻辑
    }
}

架子基本上咱们曾经搭建起来了,在解决网络申请之前先定义一个异样,专门用于解决申请响应失败的问题。

data class CustomException(val code: Int = -1, val throwable: String? = null) : Exception(throwable)

当初就得在netRequest办法中利用协程来执行网络申请、解决申请后果回调以及异样的捕捉:

fun <T> ViewModel.netRequest(block: Action<T>.() -> Unit) {
    val action = Action<T>().apply(block)

    viewModelScope.launch(CoroutineExceptionHandler { _, throwable ->
        action.error?.invoke(throwable)
    }) {
        val result = withContext(Dispatchers.IO) {
            action.request!!.invoke()
        }
        if (result.code == 0) {
            action.success?.invoke(result.data)
        } else {
            action.error?.invoke(CustomException(result.code, "申请失败"))
        }
    }
}

通过viewModelScope开启一个协程,不过咱们并没有间接在外层的launch就间接指定执行的线程,而是通过withContext指定散发器Dispatchers.IO去独自执行耗时申请,申请完结后会主动将线程从withContext指定的线程中切换到外层launch协程块所在的线程。

如果间接在外层launch间接指定Dispatchers.IO,这就会导致申请胜利action.success和申请失败action.error的执行的环境为非主线程,防止后续开发者再额定解决这种非主线程回调的状况。

通过上述一步步流程,咱们就最终搭建胜利了一个简单网络申请工具类。

搭配Retrofit提供的suspend适配器

com.squareup.retrofit2:retrofit:2.9.0这个版本的retrofit曾经适配了协程的suspend

判断是否为suspend润饰的申请办法:suspend润饰办法会在办法参数上减少一个Continuation参数:
#RequestFactory.java

HttpServiceMethod中:

具体的源码就不带大家看了,要害就在于SuspendForBody办法中的adapt办法中,外部会调用OkhttpClient#Call的办法enqueue开启线程去执行网络申请,执行结束之后会再切换到调用申请的地位所在的线程,感兴趣的请自行查看。


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:一步步基于ViewModel协程搭建通用网络请求工具

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址