KotlinコルーチンとAndroidでのコルーチンの使用の概要(3.コールバックとRxJava呼び出しを中断関数に書き換えます)

ここに画像の説明を挿入
この記事では、主に、既存プロジェクトのインターフェースコールバックロジックと、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または正常コルーチンに、またはによって回復する方法をコールバックの原理を実現するために異常なエラー。CancellableContinuationresumeresumeWithException

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できることです。コルーチンロジックを処理するためにそれ呼び出すことができますsuspendCancellableCoroutineCancellableContinuationresume、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への呼び出しは、関数呼び出しを中断し、原理は非常に簡単です、上suspendCoroutinesuspendCancellableCoroutine原則、
彼らがコールする鍵となるsuspendCoroutineUninterceptedOrReturn()機能を、その役割は、現在のコルーチンのインスタンスを取得することであり、ハング現在のコルーチンを開始するか、中断せずに結果を返します。

また、コルーチンsuspendCoroutineUninterceptedOrReturn()使用される2つの一般的な中断関数、つまりdelay()およびもありyield()ます。
delay()誰もが、精通しているyield()一時的にアプリケーションシナリオを考えていない、他のコルーチンの実行に、共同プロセスに右の現在の実装をさせることです、あなたが交互に実行され、同様の効果を達成することができます。

特定のソースコード分析では、記事の最後にある最初の記事を参照できます。

スコープ内の他の中断関数を呼び出すときも、処理ロジックを追加try-catch(注意应该加在协程体内部,在整个Scope上包try-catch是无法捕获异常的)または使用する必要があります。Kotlinは、チェックされた例外はないと主張していますが、プロセスのロジック処理とコードの通常の操作については、呼び出し時の処理をキャプチャします。CoroutinesExceptionHandler

参照:
Kotlinコルーチン(コルーチン)完全な分析(3)、非同期コールバックのカプセル化、コルーチン間の関係とコルーチンのキャンセル
Androidのコトリンコルーチン—中断関数

元の記事82件を公開 86のような 110,000以上

おすすめ

転載: blog.csdn.net/unicorn97/article/details/105163021