从暂停函数异常返回对象

时间:2019-06-13 13:51:54

标签: android deferred kotlin-coroutines

Android项目:

摘要:

def function(data):
    data = some_transform(data)

    if condition:
        # condition should be considered invariant at time of definition
        data = transform1(data)
    else:
        data = transform2(data)

    data = yet_another_transform(data)

    return data

在线

import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.MediaType
import okhttp3.ResponseBody
import retrofit2.Response
class DefaultTransportService {
    companion object {
        private val SERVICE_UNAVAILABLE = "{\n" +
                "  \"code\": -1,\n" + // 503
                "  \"message\": \"Service unavailable\"\n" +
                "}"
        private val TAG = DefaultTransportService::class.java.name

        suspend fun executeOperation(operation: Deferred<Response<*>>): Any = withContext(Dispatchers.IO) {
            try {
                operation.await()
            } catch (e: Throwable) {
                val resultResponse = Response.error<Any>(-1, ResponseBody.create(
                        MediaType.parse("application/json"),
                        SERVICE_UNAVAILABLE
                ))
                return resultResponse
            }
        }
    }
}

我得到编译错误:

return resultResponse

但是当'return' is not allowed here 抛出任何异常时,我需要更改响应。

3 个答案:

答案 0 :(得分:1)

1-创建密封类。 返回一个密封的类,就像我已经提到过的,但是接受T 输入返回结果。

{287: [{'c_id': '1234',
        'c_n': 'demo',
        'ca_id': 'AT123',
        'crt_ts': 1598440349,
        'f_id': 331,
        'map_crt_ts': 1598440351,
        'msg_cnt': 2,
        'sign': [{'name': 'speed', 'val': 10}, {'name': 'pwr', 'val': 1417}],
        'start_ts': 1598440344,
        'type': 'na',
        'u_id': 287,
        'window': 'na'}],
 288: [{'c_id': '1234',
        'c_n': 'demo',
        'ca_id': 'AT123',
        'crt_ts': 1598440349,
        'f_id': 331,
        'map_crt_ts': 1598440351,
        'msg_cnt': 2,
        'sign': [{'name': 'speed', 'val': 9}, {'name': 'pwr', 'val': 1415}],
        'start_ts': 1598440244,
        'type': 'na',
        'u_id': 288,
        'window': 'na'},
       {'c_id': '1234',
        'c_n': 'demo',
        'ca_id': 'AT123',
        'crt_ts': 1598440349,
        'f_id': 331,
        'map_crt_ts': 1598440351,
        'msg_cnt': 2,
        'sign': [{'name': 'speed', 'val': 10}, {'name': 'pwr', 'val': 1416}],
        'start_ts': 1598440243,
        'type': 'na',
        'u_id': 288,
        'window': 'na'},
       {'c_id': '1234',
        'c_n': 'demo',
        'ca_id': 'AT172',
        'crt_ts': 1598440349,
        'f_id': 331,
        'map_crt_ts': 1598440351,
        'msg_cnt': 2,
        'sign': [{'name': 'speed.', 'val': 8.2}, {'name': 'pwr', 'val': 925}],
        'start_ts': 1598440345,
        'type': 'na',
        'u_id': 288,
        'window': 'na'}]}

2-使用

sealed class Result<out T> {

    data class Success<out T>(val result: T): Result<T>()
    data class Failure<out T>(val exception: Exception) : Result<T>()

}

答案 1 :(得分:0)

恕我直言,在您的情况下,我会让您的暂停函数返回sealed class,例如:

suspend fun doSomething(): Response =
        suspendCancellableCoroutine { cont ->
            try {
                // make some work here
                cont.resume(Response.Success())
            } catch (e: Exception) {
                val error = "Service unavailable"
                cont.resume(Response.Error(error))
                Log.e(TAG, e.message)
            }
        }

sealed class Response {
    class Success : Response()
    class Error(val message: String?) : Response()
}

答案 2 :(得分:0)

一个密封的类更显式,但是从技术上讲,您不需要一个密封的类,因为可以使用resumeWithException来传播异常。

示例:

suspend fun update() : Any = suspendCancellableCoroutine{ cont ->
    launch {
        try {
            // Some suspend functions that could throw exceptions
            val response = getData()
            parseData(response)
            cont.resume(Unit)
        }catch (e : Exception){
            cont.resumeWithException(e)
        }
    }
}

用法

try {
    network.update()
}catch (e: Exception) {
    // Handle your exceptions as usual
    when (e){
        is ParseException -> emit(Status.PARSING_ERROR)
        is NetworkException -> emit(Status.NETWORK_UNAVAILABLE
        // etc...
}