文章

Kotlin Result类

Kotlin Result类

自定义 Result 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
internal suspend inline fun <reified T> BaseRxHttp.awaitResult(timeoutMillis: Long = 0L): Result<T> {  
    return runCatching {  
        if (timeoutMillis <= 0L) {  
            asClassSuspend<T>().await()  
        } else {  
            withTimeout(timeoutMillis) {  
                asClassSuspend<T>().await()  
            }  
        }  
    }  
}  
  
@OptIn(ExperimentalContracts::class)  
@SinceKotlin("1.3")  
internal inline fun <T> Result<T>.onFailure(  
    crossinline action: (exception: Throwable, isTimeout: Boolean) -> Unit  
): Result<T> {  
    contract {  
        callsInPlace(action, InvocationKind.AT_MOST_ONCE)  
    }  
    exceptionOrNull()?.let {  
        if (it is kotlinx.coroutines.TimeoutCancellationException) {  
            action(it, true)  
        } else {  
            action(it, false)  
        }  
    }  
    return this  
}  
  
  
// region AppWidget 专用  
  
@OptIn(ExperimentalContracts::class)  
inline fun <T> Result<AppWidgetData<T>>.onAppWidgetSuccess(action: (value: AppWidgetData<T>) -> Unit): Result<AppWidgetData<T>> {  
    contract {  
        callsInPlace(action, InvocationKind.AT_MOST_ONCE)  
    }  
    if (isSuccess) {  
        val data = getOrNull()  
        if (data != null && data.isValid()) {  
            WidgetMonitor.requestDataStatus(data.appWidgetLayoutCode, false)  
            action(data)  
        }  
    }  
    return this  
}  
  
@OptIn(ExperimentalContracts::class)  
internal inline fun <T> Result<AppWidgetData<T>>.onAppWidgetFailure(  
    crossinline action: (e: Throwable, value: AppWidgetData<T>) -> Unit  
): Result<AppWidgetData<T>> {  
    contract {  
        callsInPlace(action, InvocationKind.AT_MOST_ONCE)  
    }  
    if (isSuccess) {  
        val data = getOrNull()  
        if (data != null && !data.isValid()) {  
            WidgetMonitor.requestDataStatus(data.appWidgetLayoutCode, true)  
            action(data.tr ?: Throwable("data is invalid"), data)  
        }  
    }  
    return this  
}  
  
internal suspend inline fun <reified T> BaseRxHttp.awaitAppWidgetResult(  
    @AppWidgetLayoutCode  
    appWidgetLayoutCode: String,  
    callType: String? = "",  
): Result<AppWidgetData<T>> {  
    val s = SystemClock.elapsedRealtime()  
    return try {  
        callType?.let {  
            WidgetMonitor.requestData(appWidgetLayoutCode, it)  
        }  
        val data = asClassSuspend<T>().await()  
        val cost = SystemClock.elapsedRealtime() - s  
        WidgetMonitor.requestDataCost(appWidgetLayoutCode, callType, cost)  
        Result.success(  
            AppWidgetData(  
                appWidgetLayoutCode = appWidgetLayoutCode,  
                callType = callType,  
                data = data,  
                cost = cost  
            )  
        )  
    } catch (e: Throwable) {  
        val cost = SystemClock.elapsedRealtime() - s  
        WidgetMonitor.requestDataCost(appWidgetLayoutCode, callType, cost)  
        Result.success(  
            AppWidgetData(  
                appWidgetLayoutCode = appWidgetLayoutCode,  
                callType = callType,  
                data = null,  
                cost = cost,  
                tr = e  
            )  
        )  
    }  
}  
  
data class AppWidgetData<T>(  
    @AppWidgetLayoutCode  
    val appWidgetLayoutCode: String,  
    val callType: String? = "",  
    val data: T? = null,  
    val cost: Long = 0L,  
    val tr: Throwable? = null  
) {  
    fun isValid(): Boolean {  
        return data != null  
    }  
  
    fun isSuccess(): Boolean {  
        return tr == null && data != null  
    }  
}  
// endregion

awaitAppWidgetResult和jacoco插件编译不过问题

Result 扩展

本文由作者按照 CC BY 4.0 进行授权