
簡介
- suspendCoroutine 的使用
- suspendCancellableCoroutine的使用
- Retrofit是如何支持協(xié)程的
suspendCoroutine 的使用
這里我們將使用suspendCoroutine將單一方法的接口方法改造成具有返回值的方法
單一方法的回調(diào)
聲明一個單一方法的接口
/**
* @author : zhangqi
* @time : 6/22/21
* desc : 單一方法接口
*/
interface SingleMethodCallback {
fun onCallBack(value: String)
}
接著模擬一個耗時的操作,當(dāng)操作完畢我們把結(jié)果回調(diào)給實現(xiàn)類
/**
* 模擬一個耗時操作
*/
private fun runTask(callback: SingleMethodCallback) {
thread {
Thread.sleep(1000)
callback.onCallBack("result")
}
}
最后我們調(diào)用runTask方法,傳入SingleMethodCallback的實現(xiàn)
private fun runTaskDefault() {
runTask(object : SingleMethodCallback {
override fun onCallBack(value: String) {
TODO("Not yet implemented")
}
})
}
接著我們使用Kotlin協(xié)程提供的 suspendCoroutine 讓runTaskDefault具有返回值;
改造一下runTaskDefault ---> runTaskWithSuspend
suspend fun runTaskWithSuspend(): String {
// suspendCoroutine是一個掛起函數(shù)
return suspendCoroutine { continuation ->
runTask(object : SingleMethodCallback {
override fun onCallBack(value: String) {
continuation.resume(value)
}
})
}
}
這里 suspendCoroutine是一個掛起函數(shù),掛起函數(shù)只能在協(xié)程或者其他掛起函數(shù)中被調(diào)用,同時我們在回調(diào)中將結(jié)果值傳入到Coutination的resume方法中;
經(jīng)過我們上述的操作將回調(diào)方法具有返回值了;
suspendCancellableCoroutine 的使用
Success And Failure 類別的接口
聲明 success and failure 類型的接口
/**
* @author : zhangqi
* @time : 6/22/21
* desc :
*/
interface ICallBack {
fun onSuccess(data: String)
fun onFailure(t: Throwable)
}
同樣我們模擬一個耗時操作,在獲取結(jié)果的時候 調(diào)用 onSuccess()將結(jié)果回調(diào)給實現(xiàn),出現(xiàn)錯誤調(diào)用onFailure將錯誤交給實現(xiàn)處理
/**
* 模擬一個耗時操作
*/
private fun request(callback: ICallBack) {
thread {
try {
callback.onSuccess("success")
} catch (e: Exception) {
callback.onFailure(e)
}
}
}
最后我們調(diào)用requet方法,傳入接口的實現(xiàn),
private fun requestDefault() {
request(object : ICallBack {
override fun onSuccess(data: String) {
// doSomething
}
override fun onFailure(t: Throwable) {
// handle Exception
}
})
}
同樣我們使用Kotlin協(xié)程提供的掛起函數(shù)將 requestDefault()改造成 具有返回值的函數(shù) requestWithSuspend()
只不過我們這里使用了 suspendCancellablkeCoroutine ,代碼上見吧!
private suspend fun requestWithSuspend(): String {
return suspendCancellableCoroutine { cancellableContinuation->
request(object : ICallBack {
override fun onSuccess(data: String) {
cancellableContinuation.resume(data)
}
override fun onFailure(t: Throwable) {
cancellableContinuation.resumeWithException(t)
}
})
}
}
suspendCancellableCoroutine 是一個掛起函數(shù),我們將requestWithSuspend聲明稱掛起函數(shù)
在onSucess()中我們我們調(diào)用CancellableContinue # resume 方法將結(jié)果返回,在onFailure調(diào)用CancellableContinuation # resumeWithException 將異常傳入進(jìn)去;
調(diào)用requestWithSuspend()
private fun runRequestSuspend() {
try {
viewModelScope.launch {
val value = requestWithSuspend()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
在ViewModel中Kotlin協(xié)程提供了 viewModelScope 來開啟一個協(xié)程,改協(xié)程是具有聲明周期的與當(dāng)前ViewModel保持一致;
這里我們使用了try{}catch 將我們開啟的協(xié)程處理了下,調(diào)用成功獲取到value值,出現(xiàn)錯誤我們在catch塊中除了一下;
以上就是 我們兩種日常遇見頻率較高的情況進(jìn)行的改造(回調(diào)方法具有返回值)
Retrofit是如何支持協(xié)程的
Retrofit是在2.6版本開始支持,我們先對比下使用協(xié)程前后的區(qū)別
使用協(xié)前
/**
* 發(fā)現(xiàn)頁面的數(shù)據(jù)
*/
@GET("/api/v7/index/tab/discovery")
fun getDiscoveryData(): Call<OpenEyeResponse>
// 在ViewModel中調(diào)用
/**
* 沒有使用協(xié)程做網(wǎng)絡(luò)請求
*/
fun getDiscoverData() {
WidgetService.openEyeInstance.getDiscoveryData().enqueue(object : Callback<OpenEyeResponse> {
override fun onResponse(call: Call<OpenEyeResponse>, response: Response<OpenEyeResponse>) {
var body = response.body()
}
override fun onFailure(call: Call<OpenEyeResponse>, t: Throwable) {
}
})
}
接著我們看下使用協(xié)程后
使用協(xié)程后
/**
* 通過協(xié)程做本次請求
* @return OpenEyeResponse
*/
@GET("/api/v7/index/tab/discovery")
suspend fun getDiscoveryDataCoroutine(): OpenEyeResponse
/**
* 使用協(xié)程做的請求
*/
fun getDiscoverDataWithCoroutine() {
try {
viewModelScope.launch {
var discoveryDataCoroutine = WidgetService.openEyeInstance.getDiscoveryDataCoroutine()
}
} catch (e: Exception) {
}
}
可以看見,在接口類中聲明的方法聲明為掛起函數(shù),同時我們可以將我們想要的數(shù)據(jù)結(jié)構(gòu)直接返回不用Call包一層;
Retrofit支持協(xié)程
Retrofit # HttpServiceMethod
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
// 當(dāng)是直接返回數(shù)據(jù)結(jié)構(gòu)走這里
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
// 執(zhí)行了 SuspendForResponse
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
SuspendForResponse ---> KotlinExtensions.awaitResponse
SuspendForResponse(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, Call<ResponseT>> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override
protected Object adapt(Call<ResponseT> call, Object[] args) {
call = callAdapter.adapt(call);
//noinspection unchecked Checked by reflection inside RequestFactory.
Continuation<Response<ResponseT>> continuation =
(Continuation<Response<ResponseT>>) args[args.length - 1];
// See SuspendForBody for explanation about this try/catch.
try {
// 在這里直接調(diào)用了 KotlinExtensions.awaitResponse
return KotlinExtensions.awaitResponse(call, continuation);
} catch (Exception e) {
return KotlinExtensions.suspendAndThrow(e, continuation);
}
}
KotlinExtensions.awaitResponse
suspend fun <T> Call<T>.awaitResponse(): Response<T> {
// 在這里使用了suspendCancellableCoroutine
return suspendCancellableCoroutine { continuation ->
// 當(dāng)我們開啟的協(xié)程開啟了之后,會回調(diào)到這個方法
// 取消當(dāng)前的請求
continuation.invokeOnCancellation {
cancel()
}
enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
// 當(dāng)成功拿到response之后 將response返回
continuation.resume(response)
}
override fun onFailure(call: Call<T>, t: Throwable) {
// 失敗的話 直接將異常拋出
continuation.resumeWithException(t)
}
})
}
}