1
0
Эх сурвалжийг харах

修复并发择优导致作用域其他网络请求被取消的问题

drake 4 жил өмнө
parent
commit
f8fba71c75

+ 1 - 1
README.md

@@ -105,7 +105,7 @@ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
 implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
 
 // 支持自动下拉刷新和缺省页的(可选)
-implementation 'com.github.liangjingkanji:BRV:1.3.12'
+implementation 'com.github.liangjingkanji:BRV:1.3.13'
 
 implementation 'com.github.liangjingkanji:Net:2.2.20'
 ```

+ 1 - 1
build.gradle

@@ -19,7 +19,7 @@
 buildscript {
     ext {
         kotlin_version = '1.4.10'
-        brv_version = '1.3.12'
+        brv_version = '1.3.13'
         coroutine_version = '1.3.7'
         glide_version = '4.9.0'
         room_version = "2.2.5"

+ 31 - 0
docs/fastest.md

@@ -19,8 +19,34 @@ scopeNetLife {
 }
 ```
 
+
+## 取消剩余
+
+上面的示例代码实际上不会在获取到最快的结果后自动取消请求, 我们需要手动设置uid才可以
+
+```kotlin
+scopeNetLife {
+    // 同时发起四个网络请求
+    val deferred2 = Get<String>("api", uid = "最快")
+    val deferred3 = Post<String>("api", uid = "最快")
+    val deferred = Get<String>("api0", uid = "最快") // 错误接口
+    val deferred1 = Get<String>("api1", uid = "最快") // 错误接口
+
+    // 只返回最快的请求结果
+    tv_fragment.text = fastest(listOf(deferred, deferred1, deferred2, deferred3), "最快")
+}
+```
+
+网络请求的取消本质上依靠uid来辨别,如果设置[uid]参数就可以在返回最快结果后取消掉其他网络请求, 反之不会取消其他网络请求
+<br>
+
+!!! note
+    uid可以是任何类型任何值, 只有请求的`uid`和`fastest`函数的uid参数等于即可
+
 <br>
 
+## 类型不一致
+
 假设并发的接口返回的数据类型不同  或者 想要监听最快请求返回的结果回调请使用[transform](api/net/com.drake.net.utils/kotlinx.coroutines.-coroutine-scope/fastest.md)函数
 
 ```kotlin
@@ -42,6 +68,11 @@ scopeNetLife {
 
 有的场景下并发的接口返回的数据类型不同, 但是fastest只能返回一个类型, 我们可以使`transform`的回调函数返回结果都拥有一个共同的接口, 然后去类型判断
 
+<br>
+
+!!! note
+    只有最快返回结果的网络请求(或异步任务)的`transform`回调才会被执行到
+
 ## 捕获Fastest
 ```kotlin
 scopeNetLife {

+ 1 - 7
kalle/src/main/java/com/yanzhenjie/kalle/Canceller.kt

@@ -16,13 +16,7 @@
 package com.yanzhenjie.kalle
 
 interface Canceller {
-    /**
-     * Cancel operation.
-     */
-    fun cancel()
 
-    /**
-     * Operation is canceled.
-     */
+    fun cancel()
     val isCancelled: Boolean
 }

+ 1 - 1
kalle/src/main/java/com/yanzhenjie/kalle/download/BodyWorker.java

@@ -40,7 +40,7 @@ public class BodyWorker extends BasicWorker<BodyDownload> {
     @Override
     public void cancel() {
         if (mCall != null && !mCall.isCanceled()) {
-            mCall.asyncCancel();
+            mCall.cancel();
         }
     }
 

+ 1 - 1
kalle/src/main/java/com/yanzhenjie/kalle/download/UrlWorker.java

@@ -40,7 +40,7 @@ public class UrlWorker extends BasicWorker<UrlDownload> {
     @Override
     public void cancel() {
         if (mCall != null && !mCall.isCanceled()) {
-            mCall.asyncCancel();
+            mCall.cancel();
         }
     }
 

+ 1 - 1
kalle/src/main/java/com/yanzhenjie/kalle/simple/BodyWorker.java

@@ -41,7 +41,7 @@ final class BodyWorker<S, F> extends BasicWorker<SimpleBodyRequest, S, F> {
     @Override
     public void cancel() {
         if (mCall != null && !mCall.isCanceled()) {
-            mCall.asyncCancel();
+            mCall.cancel();
         }
     }
 

+ 1 - 1
kalle/src/main/java/com/yanzhenjie/kalle/simple/UrlWorker.java

@@ -41,7 +41,7 @@ final class UrlWorker<S, F> extends BasicWorker<SimpleUrlRequest, S, F> {
     @Override
     public void cancel() {
         if (mCall != null && !mCall.isCanceled()) {
-            mCall.asyncCancel();
+            mCall.cancel();
         }
     }
 

+ 21 - 76
net/src/main/java/com/drake/net/utils/Fastest.kt

@@ -21,30 +21,35 @@ import com.yanzhenjie.kalle.NetCancel
 import kotlinx.coroutines.*
 import kotlinx.coroutines.sync.Mutex
 import kotlinx.coroutines.sync.withLock
+import java.util.concurrent.CancellationException
 
 
 /**
- * 该函数将选择[deferredArray]中的Deferred执行[Deferred.await], 然后将返回最快的结果
+ * 该函数将选择[listDeferred]中的Deferred执行[Deferred.await], 然后将返回最快的结果
  * 执行过程中的异常将被忽略, 如果全部抛出异常则将抛出最后一个Deferred的异常
  *
- * @param deferredArray 一系列并发任务
+ * @param uid 指定该值将在成功返回结果后取消掉对应uid的网络请求
+ * @param listDeferred 一系列并发任务
  */
 @OptIn(ExperimentalCoroutinesApi::class)
 @Suppress("SuspendFunctionOnCoroutineScope")
-suspend fun <T> CoroutineScope.fastest(vararg deferredArray: Deferred<T>): T {
+suspend fun <T> CoroutineScope.fastest(
+    listDeferred: List<Deferred<T>>,
+    uid: Any? = null
+): T {
     val deferred = CompletableDeferred<T>()
     val mutex = Mutex()
-    deferredArray.forEach {
+    listDeferred.forEach {
         launch(Dispatchers.IO) {
             try {
                 val result = it.await()
                 mutex.withLock {
-                    NetCancel.cancel(coroutineContext[CoroutineExceptionHandler])
+                    NetCancel.cancel(uid)
                     deferred.complete(result)
                 }
             } catch (e: Exception) {
                 it.cancel()
-                val allFail = deferredArray.all { it.isCancelled }
+                val allFail = listDeferred.all { it.isCancelled }
                 if (allFail) deferred.completeExceptionally(e) else {
                     if (e !is CancellationException) e.printStackTrace()
                 }
@@ -54,91 +59,31 @@ suspend fun <T> CoroutineScope.fastest(vararg deferredArray: Deferred<T>): T {
     return deferred.await()
 }
 
-/**
- * 该函数将选择[deferredArray]中的Deferred执行[Deferred.await], 然后将返回最快的结果
- * 执行过程中的异常将被忽略, 如果全部抛出异常则将抛出最后一个Deferred的异常
- *
- * @param deferredArray 一系列并发任务
- */
-@OptIn(ExperimentalCoroutinesApi::class)
-@Suppress("SuspendFunctionOnCoroutineScope")
-suspend fun <T> CoroutineScope.fastest(deferredArray: List<Deferred<T>>): T {
-    val deferred = CompletableDeferred<T>()
-    val mutex = Mutex()
-    deferredArray.forEach {
-        launch(Dispatchers.IO) {
-            try {
-                val result = it.await()
-                mutex.withLock {
-                    NetCancel.cancel(coroutineContext[CoroutineExceptionHandler])
-                    deferred.complete(result)
-                }
-            } catch (e: Exception) {
-                it.cancel()
-                val allFail = deferredArray.all { it.isCancelled }
-                if (allFail) deferred.completeExceptionally(e) else {
-                    if (e !is CancellationException) e.printStackTrace()
-                }
-            }
-        }
-    }
-    return deferred.await()
-}
 
 /**
- * 该函数将选择[deferredArray]中的Deferred执行[Deferred.await], 然后将返回最快的结果
+ * 该函数将选择[listDeferred]中的Deferred执行[Deferred.await], 然后将返回最快的结果
  * 执行过程中的异常将被忽略, 如果全部抛出异常则将抛出最后一个Deferred的异常
  *
  * @see DeferredTransform 允许监听[Deferred]返回数据回调
- * @param deferredArray 一系列并发任务
- */
-@OptIn(ExperimentalCoroutinesApi::class)
-@Suppress("SuspendFunctionOnCoroutineScope")
-suspend fun <T, R> CoroutineScope.fastest(vararg deferredArray: DeferredTransform<T, R>): R {
-    val deferred = CompletableDeferred<R>()
-    val mutex = Mutex()
-    deferredArray.forEach {
-        launch(Dispatchers.IO) {
-            try {
-                val result = it.deferred.await()
-                mutex.withLock {
-                    NetCancel.cancel(coroutineContext[CoroutineExceptionHandler])
-                    if (!deferred.isCompleted) {
-                        val transformResult = it.block(result)
-                        deferred.complete(transformResult)
-                    }
-                }
-            } catch (e: Exception) {
-                it.deferred.cancel()
-                val allFail = deferredArray.all { it.deferred.isCancelled }
-                if (allFail) deferred.completeExceptionally(e) else {
-                    if (e !is CancellationException) e.printStackTrace()
-                }
-            }
-        }
-    }
-    return deferred.await()
-}
-
-/**
- * 该函数将选择[deferredList]中的Deferred执行[Deferred.await], 然后将返回最快的结果
- * 执行过程中的异常将被忽略, 如果全部抛出异常则将抛出最后一个Deferred的异常
  *
- * @see DeferredTransform 允许监听[Deferred]返回数据回调
- * @param deferredList 一系列并发任务
+ * @param uid 指定该值将在成功返回结果后取消掉对应uid的网络请求
+ * @param listDeferred 一系列并发任务
  */
 @JvmName("fastestTransform")
 @OptIn(ExperimentalCoroutinesApi::class)
 @Suppress("SuspendFunctionOnCoroutineScope")
-suspend fun <T, R> CoroutineScope.fastest(deferredList: List<DeferredTransform<T, R>>): R {
+suspend fun <T, R> CoroutineScope.fastest(
+    listDeferred: List<DeferredTransform<T, R>>,
+    uid: Any? = null
+): R {
     val deferred = CompletableDeferred<R>()
     val mutex = Mutex()
-    deferredList.forEach {
+    listDeferred.forEach {
         launch(Dispatchers.IO) {
             try {
                 val result = it.deferred.await()
                 mutex.withLock {
-                    NetCancel.cancel(coroutineContext[CoroutineExceptionHandler])
+                    NetCancel.cancel(uid)
                     if (!deferred.isCompleted) {
                         val transformResult = it.block(result)
                         deferred.complete(transformResult)
@@ -146,7 +91,7 @@ suspend fun <T, R> CoroutineScope.fastest(deferredList: List<DeferredTransform<T
                 }
             } catch (e: Exception) {
                 it.deferred.cancel()
-                val allFail = deferredList.all { it.deferred.isCancelled }
+                val allFail = listDeferred.all { it.deferred.isCancelled }
                 if (allFail) deferred.completeExceptionally(e) else {
                     if (e !is CancellationException) e.printStackTrace()
                 }

+ 15 - 9
sample/src/main/java/com/drake/net/sample/ui/fragment/FastestFragment.kt

@@ -26,13 +26,15 @@ import com.drake.net.Post
 import com.drake.net.sample.R
 import com.drake.net.utils.fastest
 import com.drake.net.utils.scopeNetLife
-import kotlinx.android.synthetic.main.fragment_fastest.*
+import kotlinx.android.synthetic.main.fragment_request_method.*
 
 class FastestFragment : Fragment() {
 
-    override fun onCreateView(inflater: LayoutInflater,
-                              container: ViewGroup?,
-                              savedInstanceState: Bundle?): View? {
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
         return inflater.inflate(R.layout.fragment_fastest, container, false)
     }
 
@@ -40,15 +42,19 @@ class FastestFragment : Fragment() {
         super.onActivityCreated(savedInstanceState)
 
         scopeNetLife {
+            /*
+            网络请求的取消本质上依靠uid来辨别,如果设置[uid]参数可以在返回最快结果后取消掉其他网络请求, 反之不会取消其他网络请求
+            Tip: uid可以是任何值
+            */
 
             // 同时发起四个网络请求
-            val deferred = Get<String>("api0") // 错误接口
-            val deferred1 = Get<String>("api1") // 错误接口
-            val deferred2 = Get<String>("api")
-            val deferred3 = Post<String>("api")
+            val deferred2 = Get<String>("api", uid = "最快")
+            val deferred3 = Post<String>("api", uid = "最快")
+            val deferred = Get<String>("api0", uid = "最快") // 错误接口
+            val deferred1 = Get<String>("api1", uid = "最快") // 错误接口
 
             // 只返回最快的请求结果
-            tv_fragment.text = fastest(deferred, deferred1, deferred2, deferred3)
+            tv_fragment.text = fastest(listOf(deferred, deferred1, deferred2, deferred3), "最快")
         }
 
         /*