教你如何使用协程(六)协程的异常处理

原文地址:https://www.bennyhuo.com/2019/04/23/coroutine-exceptions/

异步代码的异常处理通常都比较让人头疼,而协程则再一次展现了它的威力。

引子

我们在前面一篇文章当中提到了这样一个例子:

typealias Callback = (User) -> Unit

fun getUser(callback: Callback){
    
    
    ...
}

我们通常会定义这样的回调接口来实现异步数据的请求,我们可以很方便的将它转换成协程的接口:

suspend fun getUserCoroutine() = suspendCoroutine<User> {
    
    
    continuation ->
    getUser {
    
    
        continuation.resume(it)
    }
}

并最终交给按钮点击事件或者其他事件去触发这个异步请求:

getUserBtn.setOnClickListener {
    
    
    GlobalScope.launch(Dispatchers.Main) {
    
    
        userNameView.text = getUserCoroutine().name
    }
}

那么问题来了,既然是请求,总会有失败的情形,而我们这里并没有对错误的处理,接下来我们就完善这个例子。

添加异常处理逻辑

首先我们加上异常回调接口函数:

interface Callback<T> {
    
    
    fun onSuccess(value: T)

    fun onError(t: Throwable)
}

接下来我们在改造一下我们的 getUserCoroutine:

suspend fun getUserCoroutine() = suspendCoroutine<User> {
    
     continuation ->
    getUser(object : Callback<User> {
    
    
        override fun onSuccess(value: User) {
    
    
            continuation.resume(value)
        }

        override fun onError(t: Throwable) {
    
    
            continuation.resumeWithException(t)
        }
    })
}

大家可以看到,我们似乎就是完全把 Callback 转换成了一个 Continuation,在调用的时候我们只需要:

GlobalScope.launch(Dispatchers.Main) {
    
    
    try {
    
    
        userNameView.text = getUserCoroutine().name
    } catch (e: Exception) {
    
    
        userNameView.text = "Get User Error: $e"
    }
}

是的,你没看错,一个异步的请求异常,我们只需要在我们的代码中捕获就可以了,这样做的好处就是,请求的全流程异常都可以在一个 try … catch … 当中捕获,那么我们可以说真正做到了把异步代码变成了同步的写法。

如果你一直在用 RxJava 处理这样的逻辑,那么你的请求接口可能是这样的:

fun getUserObservable(): Single<User> {
    
    
    return Single.create<User> {
    
     emitter ->
        getUser(object : Callback<User> {
    
    
            override fun onSuccess(value: User) {
    
    
                emitter.onSuccess(value)
            }

            override fun onError(t: Throwable) {
    
    
                emitter.onError(t)
            }
        })
    }
}

调用时大概是这样的:

getUserObservable()
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe ({
    
     user ->
            userNameView.text = user.name
        }, {
    
    
            userNameView.text = "Get User Error: $it"
        })

其实你很容易就能发现在这里 RxJava 做的事儿跟协程的目的是一样的,只不过协程用了一种更自然的方式。

也许你已经对 RxJava 很熟悉并且感到很自然,但相比之下,RxJava 的代码比协程的复杂度更高,更让人费解,这一点我们后面的文章中也会持续用例子来说明这一点。

全局异常处理

线程也好、RxJava 也好,都有全局处理异常的方式,例如:

Guess you like

Origin blog.csdn.net/abc6368765/article/details/103290216