Android Kotlin 使用协程取代回调函数(suspendCoroutine 的用法)

一、简述

如果说大家对于协程已经有些熟悉了,但是手拿一把未开封的 绝世好剑,却无法发挥真正的威力!或者大家不是很熟悉协程,还不清楚协程所带来的好处是啥?

这篇文章会为大家带来 通窍级别 的体验。

二、示例

2.1 普通写法

以获取一个 View 的宽高为例。

通常我们获取一个 View 的宽高,都是这么做的:

view.post {
	val height = view.measuredHeight
	val width = view.measuredWidth
}

因为至少需要等到 View 的布局流程走完,我们才能获得 View 的真实宽高。

那么接下来如何用协程来代替这个回调呢?各位请看:

2.2 协程写法
//	1. 创建一个 View 的扩展函数 await()
suspend fun View.await() = suspendCoroutine<View> { coroutine->
	this.post {
		//	2. 在 View.post 函数内,将本身返回
		coroutine.resume(this)
	}
}

使用(为了让大家看出效果,就放截图了):
使用
稍微的解释一下, launch() 是我自己对 GlobalScope.launch() 进行封装后的函数,这里可以看作直接开启了一个协程作用域。之后让 view 调用 await() 函数,返回的值就是宽高确定后的 View 啦。

三、带有成功和失败的回调

3.1 普通写法

我们以获取一个数据的成功或者失败为例:

fun getData(onSuccess:(String)->Unit,onFail:(Throwable)->Unit){
	Thread.sleep(1000)
	if ((Math.random() *10).toInt() % 2 == 0){
		onSuccess("数据")
	}else{
		onFail(IllegalStateException("获取数据失败"))
	}
}

使用:
使用

3.2 协程写法
suspend fun getData() = suspendCoroutine<String> {
    Thread.sleep(1000)
    if ((Math.random() *10).toInt() % 2 == 0){
        it.resume("数据")
    }else{
        it.resumeWithException(IllegalStateException("获取数据失败"))
    }
}

使用:

    GlobalScope.launch {
        val data = getData()
        //  <如果能够拿到数据,那就继续往下走>
        println("data:${data}")
    }

如果 getData() 能够成功返回数据,那么这样写是没问题的,但是 如果失败了,那就会抛出异常,所以我们必须要使用 try catch 语句

    GlobalScope.launch {
        try {
            val data = getData()
            //  <如果能够拿到数据,那就继续往下走>
            println("data:${data}")
        }catch (e:Throwable){
            //  <获取数据失败并且捕获异常>
        }
    }

对比一下之前的写法……是不是觉得还不如前面的写法呢?所以我们可以利用一下协程上下文——CoroutineConext 来搞搞事情……

3.3 使用协程上下文处理异常
  1. 我们先创建一个自定义的处理异常的上下文类:
abstract class NetErrorContext:AbstractCoroutineContextElement(CoroutineExceptionHandler),CoroutineExceptionHandler{
	
}

这是很典型很模板式的写法……
表情

不懂的话也没关系,把这个模板记下来,以后有空的话写写关于协程上下文的文章。

  1. 定义一个异常处理对象:
    val netErrorHandler = object :NetErrorContext(){
        override fun handleException(throwable: Throwable) {
            println("网络请求异常……")
        }
    }
  1. 最后在开启协程体的时候,将上下文加入:
    GlobalScope.launch(context = netErrorHandler) {
        val data = getData()
        //  <如果能够拿到数据,那就继续往下走>
        println("data:${data}")
    }

这样的话,如果有异常就会被 netErrorHandler 捕获到。而且又回到这朴实无华的写法了……

当然,你们自己自定义上下文的时候,完全可以根据自己的业务去实现一些方法,上面的例子仅仅是定义了一个 handleException() 方法,并且也只定义了一个参数,在实际开发过程中,这样还是很具有灵活性的……而且协程上下文是可以叠加的……

  • 27
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Kotlin 中,函数的参数可以分为两种类型:入参(参数)和出参(返回值)。 出参(返回值)是函数执行后返回给调用者的结果。在 Kotlin 中,通过使用 `fun` 关键字定义函数时,可以在函数签名后面使用冒号 `:` 指定函数的返回类型。例如: ```kotlin fun add(a: Int, b: Int): Int { return a + b } ``` 在上面的例子中,函数 `add` 接受两个整数参数 `a` 和 `b`,并返回它们的和。返回类型 `Int` 指定了函数的出参类型。 对于回调函数,它是一种常见的编程模式,在异步操作中经常使用。在 Kotlin 中,可以通过高阶函数(Higher-Order Function)来实现回调函数的传递。 一个简单的回调函数示例: ```kotlin fun processData(data: String, callback: (String) -> Unit) { // 模拟处理数据的操作 val processedData = data.toUpperCase() // 调用回调函数,传递处理后的结果 callback(processedData) } fun main() { val data = "Hello, world!" processData(data) { result -> println("Processed data: $result") } } ``` 在上述示例中,我们定义了一个名为 `processData` 的函数,接受一个字符串参数 `data` 和一个回调函数 `callback`。回调函数是一个接受字符串参数并不返回任何结果的函数。 在 `main` 函数中,我们调用了 `processData` 函数,并传递了一个 lambda 表达式作为回调函数。这个 lambda 表达式会在 `processData` 函数内部被调用,并打印出处理后的结果。 通过使用回调函数,我们可以在异步操作完成后得到通知,并处理操作的结果。这种模式非常适用于处理长时间运行的操作、网络请求等异步任务。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值