この記事では、主に、既存プロジェクトのインターフェースコールバックロジックと、Rxjavaのサブスクリプションロジックコードについて、サスペンドサスペンド関数の形式に変更されたものを紹介します。
記事ディレクトリ
1インターフェイスコールバックの書き換え
一般的なインターフェースコールバックシナリオでは、ネットワークインターフェースの成功と失敗のコールバック、動的アクセス許可のアプリケーションコールバック、またはその他の非同期コールバックインターフェースなど、一時停止機能の形式にすべて変更できます。
(1)suspendCoroutineを使用する
OkHttpネットワーク要求にコール参照して実施例の、完全に解決さKotlinコルーチン(コルーチン)、(III)、カプセル化解除非同期コールバックコルーチン相互関係とコルーチン物品、我々ができコールアドオブジェクトawait()
次のように、拡散機能。
suspend fun <T> Call<T>.await(): T = suspendCoroutine { cont ->
enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful) {
cont.Continuation(response.body()!!)
} else {
cont.resumeWithException(ErrorResponse(response))
}
}
override fun onFailure(call: Call<T>, t: Throwable) {
cont.resumeWithException(t)
}
})
}
即ちによってsuspendCoroutine
またはsuspendCancellableCoroutine
、その内部使用Continuation
または正常コルーチンに、またはによって回復する方法をコールバックの原理を実現するために異常なエラー。CancellableContinuation
resume
resumeWithException
public suspend inline fun <T> suspendCoroutine(crossinline block: (Continuation<T>) -> Unit): T =
suspendCoroutineUninterceptedOrReturn { c: Continuation<T> ->
val safe = SafeContinuation(c.intercepted())
block(safe)
safe.getOrThrow()
}
public suspend inline fun <T> suspendCancellableCoroutine(
crossinline block: (CancellableContinuation<T>) -> Unit
): T =
suspendCoroutineUninterceptedOrReturn { uCont ->
val cancellable = CancellableContinuationImpl(uCont.intercepted(), resumeMode = MODE_CANCELLABLE)
// 和 suspendCoroutine 的区别就在这里,如果协程已经被取消或者已完成,就会抛出 CancellationException 异常
cancellable.initCancellability()
block(cancellable)
cancellable.getResult()
}
サスペンド関数に変換するアイデアも非常に単純です。つまり、元のインターフェイスの成功とエラーのコールバックでレイヤーがカプセル化されるため、呼び出し元はコルーチンの形式を使用してインターフェイスのネストを減らすことができます。
(2)使用suspendCancellableCoroutine
上記suspendCoroutine
で紹介しsuspendCancellableCoroutine
た使用法、次に使用法を紹介しsuspendCancellableCoroutine
ます。2つの違いは、返されるオブジェクトをJob.cancel()
キャンセル(スローCancellationException
)できることです。コルーチンロジックを処理するためにそれを呼び出すことができます。suspendCancellableCoroutine
CancellableContinuation
resume、resumeWithException和抛出CancellationException
MainScope().launch {
try {
val user = fetchUser()
//由于fetchUser中产生来异常,所以下面的updateUser不会被调用到
updateUser(user)
} catch (exception: Exception) {
// Use try-catch or CoroutinesExceptionHandler to handle exceptions.
Log.d("demo", "$exception") // Prints "java.io.IOException".
}
// 如果上面使用了try-catch来捕获异常,那么下面的代码仍然可以执行到
doSomething()
}
// Fetches the user data from server.
private suspend fun fetchUser(): User = suspendCancellableCoroutine {
cancellableContinuation ->
fetchUserFromNetwork(object : Callback {
override fun onSuccess(user: User) {
cancellableContinuation.resume(user)
}
override fun onFailure(exception: Exception) {
// Invokes this line since the callback onFailure() is invoked.
cancellableContinuation.resumeWithException(exception)
}
})
}
private fun fetchUserFromNetwork(callback: Callback) {
Thread {
Thread.sleep(3_000)
//callback.onSuccess(User())
// Invokes onFailure() callback with "IOException()".
callback.onFailure(IOException())
}.start()
}
private fun updateUser(user: User) {
// Updates UI with [User] data.
}
interface Callback {
fun onSuccess(user: User)
fun onFailure(exception: Exception)
}
class User
2 RxJavaのサブスクリプションコールバックが一時停止関数に変換されます
現在、ほとんどのプロジェクトでRxJavaが使用されています。多くのテキストでは、コルーチンを使用してRxJavaを置き換えることが推奨されていますが、コルーチンAPIはまだ進化しています。一方で、現在のRxJavaコードはまだ許容範囲です。総置換コストまた、リスクが高いため、この2つを一緒に使用するのが最適です。
RxJava呼び出しからコルーチンのサスペンド関数形式への変換を容易にするために、jetbrainsは正式に実装を提供しましたkotlinx-coroutines-rx2
。
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:1.3.2"
例としてSingleの使用を取り上げ、Single.await()を呼び出すと、RxJavaを1に変換するのに役立ちsuspendCancellableCoroutine
ます。プロセスは実際には上記の変換と同じです。ソースコードは次のとおりです
。
MainScope().launch {
CoroutineScope(Dispatchers.Main).launch {
try {
val user = fetchUserFromServer().await()
updateUser(user)
} catch (e: Exception) {
Log.d("demo", "(4) {$e}, ${Thread.currentThread()}")
}
}
}
private fun fetchUserFromServer(): Single<User> =
Single.create<User> {
Log.d("demo", "(1) fetchUserFromServer start, ${Thread.currentThread()}")
Thread.sleep(3_000)
it.onSuccess(User())
Log.d("demo", "(2) fetchUserFromServer onSuccess, ${Thread.currentThread()}")
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
private fun updateUser(user: User) {
Log.d("demo", "(3) updateUser, ${Thread.currentThread()}")
}
class User
つまり、元のメソッドを変更する必要はありません。呼び出し場所kotlinx-coroutines-rx2
で定義されたawait関数を使用するだけで、現在のコルーチンの実行が一時停止され、RxJavaが結果を返した後にコルーチンの実行が再開されます。もちろん、呼び出し時に例外try-catchを追加することを忘れないでください。
RxJavaのMaybeとObservableには、kotlinx-coroutines-rx2
対応する拡張関数が用意されているので、急いでコードで試してみてください。
要約:
コールバック関数やコルーチンにRxJavaへの呼び出しは、関数呼び出しを中断し、原理は非常に簡単です、上suspendCoroutine
とsuspendCancellableCoroutine
原則、
彼らがコールする鍵となるsuspendCoroutineUninterceptedOrReturn()
機能を、その役割は、現在のコルーチンのインスタンスを取得することであり、ハング現在のコルーチンを開始するか、中断せずに結果を返します。
また、コルーチンsuspendCoroutineUninterceptedOrReturn()
で使用される2つの一般的な中断関数、つまりdelay()
およびもありyield()
ます。
delay()
誰もが、精通しているyield()
一時的にアプリケーションシナリオを考えていない、他のコルーチンの実行に、共同プロセスに右の現在の実装をさせることです、あなたが交互に実行され、同様の効果を達成することができます。
特定のソースコード分析では、記事の最後にある最初の記事を参照できます。
スコープ内の他の中断関数を呼び出すときも、処理ロジックを追加try-catch(注意应该加在协程体内部,在整个Scope上包try-catch是无法捕获异常的)
または使用する必要があります。Kotlinは、チェックされた例外はないと主張していますが、プロセスのロジック処理とコードの通常の操作については、呼び出し時の処理をキャプチャします。CoroutinesExceptionHandler
参照:
Kotlinコルーチン(コルーチン)完全な分析(3)、非同期コールバックのカプセル化、コルーチン間の関係とコルーチンのキャンセル
Androidのコトリンコルーチン—中断関数