Browse Source

获取并发最快返回结果允许监听返回回调

drake 4 years ago
parent
commit
f1bd2a8a1f
34 changed files with 305 additions and 70 deletions
  1. 15 14
      README.md
  2. 15 7
      docs/api/net/alltypes/index.md
  3. 5 2
      docs/api/net/com.drake.net.scope/-android-scope/finally.md
  4. 5 1
      docs/api/net/com.drake.net.scope/-dialog-coroutine-scope/finally.md
  5. 3 0
      docs/api/net/com.drake.net.scope/-dialog-coroutine-scope/read-cache.md
  6. 9 0
      docs/api/net/com.drake.net.scope/-net-coroutine-scope/finally.md
  7. 1 0
      docs/api/net/com.drake.net.scope/-net-coroutine-scope/index.md
  8. 3 0
      docs/api/net/com.drake.net.scope/-net-coroutine-scope/read-cache.md
  9. 5 1
      docs/api/net/com.drake.net.scope/-page-coroutine-scope/finally.md
  10. 3 0
      docs/api/net/com.drake.net.scope/-page-coroutine-scope/read-cache.md
  11. 5 1
      docs/api/net/com.drake.net.scope/-state-coroutine-scope/finally.md
  12. 3 0
      docs/api/net/com.drake.net.scope/-state-coroutine-scope/read-cache.md
  13. 5 0
      docs/api/net/com.drake.net.transform/-deferred-transform/-init-.md
  14. 5 0
      docs/api/net/com.drake.net.transform/-deferred-transform/block.md
  15. 5 0
      docs/api/net/com.drake.net.transform/-deferred-transform/deferred.md
  16. 18 0
      docs/api/net/com.drake.net.transform/-deferred-transform/index.md
  17. 15 0
      docs/api/net/com.drake.net.transform/index.md
  18. 7 0
      docs/api/net/com.drake.net.transform/kotlinx.coroutines.-deferred/index.md
  19. 5 0
      docs/api/net/com.drake.net.transform/kotlinx.coroutines.-deferred/transform.md
  20. 1 0
      docs/api/net/com.drake.net.utils/index.md
  21. 24 0
      docs/api/net/com.drake.net.utils/kotlinx.coroutines.-coroutine-scope/fastest.md
  22. 7 0
      docs/api/net/com.drake.net.utils/kotlinx.coroutines.-coroutine-scope/index.md
  23. 1 1
      docs/api/net/index.md
  24. 4 1
      docs/api/net/package-list
  25. 0 25
      docs/fast-select.md
  26. 48 0
      docs/fastest.md
  27. 1 2
      mkdocs.yml
  28. 29 0
      net/src/main/java/com/drake/net/transform/DeferredTransform.kt
  29. 39 0
      net/src/main/java/com/drake/net/utils/ScopeUtils.kt
  30. 11 7
      sample/src/main/java/com/drake/net/sample/ui/fragment/FastestFragment.kt
  31. 0 0
      sample/src/main/res/drawable/ic_fastest.xml
  32. 1 1
      sample/src/main/res/layout/fragment_fastest.xml
  33. 2 2
      sample/src/main/res/menu/menu_main.xml
  34. 5 5
      sample/src/main/res/navigation/nav_main.xml

+ 15 - 14
README.md

@@ -19,35 +19,40 @@
 
 
 
-Android上 最强网络任务库, 创新式的网络请求库(针对[Kalle](https://github.com/yanzhenjie/Kalle)网络请求框架进行扩展), 支持协程高并发网络请求
+Android上不是最强网络任务库, 创新式的网络请求库(针对[Kalle](https://github.com/yanzhenjie/Kalle)网络请求框架进行扩展), 支持协程高并发网络请求 <br>
 
 <br>
 
 
 
-Net 1.0+ 版本为RxJava实现 <br>
-Net 2.0+ 版本开始引入Kotlin协程特性, 开发者无需掌握协程也可以使用
+Net 1.x 版本为RxJava实现 <br>
+Net 2.x 版本为协程实现(开发者无需掌握协程也可以使用)
 
 
 
-目前正在进行的任务
-
-- [ ] Okhttp4.8重构
-- [ ] 插件拦截网络日志
+正在进行的任务
 
+- OkHttp4.8 重构
+- 开发网络日志插件解决`LogCat`输出缺陷
 
+<br>
 
 主要新增特性
 
+- 代码优雅
+- 文档详细
+- Kotlin
 - 协程
 - 并发网络请求
 - 串行网络请求
 - 切换线程
 - DSL编程
+- 支持先强制读取缓存后网络请求二次刷新
+- 并发请求返回最快请求结果(可返回不同响应数据)
 - 方便的缓存处理
 - 自动错误信息吐司
 - 自动异常捕获
-- 自动日志打印异常
+- 自动日志打印异常(任何网络错误可追踪到具体请求接口)
 - 自动JSON解析
 - 自动处理下拉刷新和上拉加载
 - 自动处理分页加载
@@ -55,9 +60,7 @@ Net 2.0+ 版本开始引入Kotlin协程特性, 开发者无需掌握协程也可
 - 自动处理生命周期
 - 自动处理加载对话框
 - 协程作用域支持错误和结束回调
-- 支持先强制读取缓存后网络请求二次刷新
-- 多个并发请求返回最快请求结果
-- 附带超强轮循器
+- 内置超强轮循器(计时器)
 
 
 
@@ -81,8 +84,6 @@ Net 2.0+ 版本开始引入Kotlin协程特性, 开发者无需掌握协程也可
 
 
 
-
-
 <br>
 
 在项目根目录的 build.gradle 添加仓库
@@ -106,7 +107,7 @@ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
 // 支持自动下拉刷新和缺省页的(可选)
 implementation 'com.github.liangjingkanji:BRV:1.3.8'
 
-implementation 'com.github.liangjingkanji:Net:2.2.10'
+implementation 'com.github.liangjingkanji:Net:2.2.11'
 ```
 
 <br>

+ 15 - 7
docs/api/net/alltypes/index.md

@@ -36,6 +36,11 @@
 ##### [kotlinx.coroutines.CoroutineScope](../com.drake.net.error/kotlinx.coroutines.-coroutine-scope/index.md)
 
 
+| (extensions in package com.drake.net.utils)
+
+##### [kotlinx.coroutines.CoroutineScope](../com.drake.net.utils/kotlinx.coroutines.-coroutine-scope/index.md)
+
+
 | (extensions in package com.drake.net.utils)
 
 ##### [android.database.Cursor](../com.drake.net.utils/android.database.-cursor/index.md)
@@ -48,6 +53,16 @@
 默认的转换器实现, 如果不满足需求建议将该文件复制到项目中修改
 
 
+| (extensions in package com.drake.net.transform)
+
+##### [kotlinx.coroutines.Deferred](../com.drake.net.transform/kotlinx.coroutines.-deferred/index.md)
+
+
+|
+
+##### [com.drake.net.transform.DeferredTransform](../com.drake.net.transform/-deferred-transform/index.md)
+
+
 |
 
 ##### [com.drake.net.scope.DialogCoroutineScope](../com.drake.net.scope/-dialog-coroutine-scope/index.md)
@@ -110,13 +125,6 @@ Net的全局配置
 自动显示网络错误信息协程作用域
 
 
-|
-
-##### [com.drake.net.connect.OkHttpConnectFactory](../com.drake.net.connect/-ok-http-connect-factory/index.md)
-
-Created by Zhenjie Yan on 2016/10/15.
-
-
 |
 
 ##### [com.drake.net.scope.PageCoroutineScope](../com.drake.net.scope/-page-coroutine-scope/index.md)

+ 5 - 2
docs/api/net/com.drake.net.scope/-android-scope/finally.md

@@ -2,8 +2,11 @@
 
 # finally
 
-`protected var finally: (`[`AndroidScope`](index.md)`.(`[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`?) -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`)?`
-`protected open fun finally(e: `[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`open fun finally(block: `[`AndroidScope`](index.md)`.(`[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`?) -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)` = {}): `[`AndroidScope`](index.md)
+`protected var finally: (`[`AndroidScope`](index.md)`.(`[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`?) -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`)?``protected open fun finally(e: `[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)
+
+### Parameters
+
+`e` - 如果发生异常导致作用域执行完毕, 则该参数为该异常对象, 正常结束则为null`open fun finally(block: `[`AndroidScope`](index.md)`.(`[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`?) -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)` = {}): `[`AndroidScope`](index.md)
 
 无论正常或者异常结束都将最终执行
 

+ 5 - 1
docs/api/net/com.drake.net.scope/-dialog-coroutine-scope/finally.md

@@ -2,4 +2,8 @@
 
 # finally
 
-`protected fun finally(e: `[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)
+`protected fun finally(e: `[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)
+
+### Parameters
+
+`e` - 如果发生异常导致作用域执行完毕, 则该参数为该异常对象, 正常结束则为null

+ 3 - 0
docs/api/net/com.drake.net.scope/-dialog-coroutine-scope/read-cache.md

@@ -6,3 +6,6 @@
 
 读取缓存回调
 
+### Parameters
+
+`succeed` - 缓存是否成功

+ 9 - 0
docs/api/net/com.drake.net.scope/-net-coroutine-scope/finally.md

@@ -0,0 +1,9 @@
+[net](../../index.md) / [com.drake.net.scope](../index.md) / [NetCoroutineScope](index.md) / [finally](./finally.md)
+
+# finally
+
+`protected open fun finally(e: `[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)
+
+### Parameters
+
+`e` - 如果发生异常导致作用域执行完毕, 则该参数为该异常对象, 正常结束则为null

+ 1 - 0
docs/api/net/com.drake.net.scope/-net-coroutine-scope/index.md

@@ -29,6 +29,7 @@
 | [cache](cache.md) | 该函数一般用于缓存读取 只在第一次启动作用域时回调 该函数在作用域[launch](launch.md)之前执行 函数内部所有的异常都不会被抛出, 也不会终止作用域执行`fun cache(error: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)` = false, animate: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)` = false, onCache: suspend CoroutineScope.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`AndroidScope`](../-android-scope/index.md) |
 | [cancel](cancel.md) | `open fun cancel(cause: CancellationException?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) |
 | [catch](catch.md) | `open fun catch(e: `[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) |
+| [finally](finally.md) | `open fun finally(e: `[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) |
 | [handleError](handle-error.md) | 错误处理`open fun handleError(e: `[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) |
 | [launch](launch.md) | `open fun launch(block: suspend CoroutineScope.() -> `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)`): `[`NetCoroutineScope`](./index.md) |
 | [readCache](read-cache.md) | 读取缓存回调`open fun readCache(succeed: `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html)`): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html) |

+ 3 - 0
docs/api/net/com.drake.net.scope/-net-coroutine-scope/read-cache.md

@@ -6,3 +6,6 @@
 
 读取缓存回调
 
+### Parameters
+
+`succeed` - 缓存是否成功

+ 5 - 1
docs/api/net/com.drake.net.scope/-page-coroutine-scope/finally.md

@@ -2,4 +2,8 @@
 
 # finally
 
-`protected fun finally(e: `[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)
+`protected fun finally(e: `[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)
+
+### Parameters
+
+`e` - 如果发生异常导致作用域执行完毕, 则该参数为该异常对象, 正常结束则为null

+ 3 - 0
docs/api/net/com.drake.net.scope/-page-coroutine-scope/read-cache.md

@@ -6,3 +6,6 @@
 
 读取缓存回调
 
+### Parameters
+
+`succeed` - 缓存是否成功

+ 5 - 1
docs/api/net/com.drake.net.scope/-state-coroutine-scope/finally.md

@@ -2,4 +2,8 @@
 
 # finally
 
-`protected fun finally(e: `[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)
+`protected fun finally(e: `[`Throwable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/index.html)`?): `[`Unit`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html)
+
+### Parameters
+
+`e` - 如果发生异常导致作用域执行完毕, 则该参数为该异常对象, 正常结束则为null

+ 3 - 0
docs/api/net/com.drake.net.scope/-state-coroutine-scope/read-cache.md

@@ -6,3 +6,6 @@
 
 读取缓存回调
 
+### Parameters
+
+`succeed` - 缓存是否成功

+ 5 - 0
docs/api/net/com.drake.net.transform/-deferred-transform/-init-.md

@@ -0,0 +1,5 @@
+[net](../../index.md) / [com.drake.net.transform](../index.md) / [DeferredTransform](index.md) / [&lt;init&gt;](./-init-.md)
+
+# &lt;init&gt;
+
+`DeferredTransform(deferred: Deferred<T>, block: (T) -> T = { it })`

+ 5 - 0
docs/api/net/com.drake.net.transform/-deferred-transform/block.md

@@ -0,0 +1,5 @@
+[net](../../index.md) / [com.drake.net.transform](../index.md) / [DeferredTransform](index.md) / [block](./block.md)
+
+# block
+
+`val block: (T) -> T`

+ 5 - 0
docs/api/net/com.drake.net.transform/-deferred-transform/deferred.md

@@ -0,0 +1,5 @@
+[net](../../index.md) / [com.drake.net.transform](../index.md) / [DeferredTransform](index.md) / [deferred](./deferred.md)
+
+# deferred
+
+`val deferred: Deferred<T>`

+ 18 - 0
docs/api/net/com.drake.net.transform/-deferred-transform/index.md

@@ -0,0 +1,18 @@
+[net](../../index.md) / [com.drake.net.transform](../index.md) / [DeferredTransform](./index.md)
+
+# DeferredTransform
+
+`data class DeferredTransform<T>`
+
+### Constructors
+
+| Name | Summary |
+|---|---|
+| [&lt;init&gt;](-init-.md) | `DeferredTransform(deferred: Deferred<T>, block: (T) -> T = { it })` |
+
+### Properties
+
+| Name | Summary |
+|---|---|
+| [block](block.md) | `val block: (T) -> T` |
+| [deferred](deferred.md) | `val deferred: Deferred<T>` |

+ 15 - 0
docs/api/net/com.drake.net.transform/index.md

@@ -0,0 +1,15 @@
+[net](../index.md) / [com.drake.net.transform](./index.md)
+
+## Package com.drake.net.transform
+
+### Types
+
+| Name | Summary |
+|---|---|
+| [DeferredTransform](-deferred-transform/index.md) | `data class DeferredTransform<T>` |
+
+### Extensions for External Classes
+
+| Name | Summary |
+|---|---|
+| [kotlinx.coroutines.Deferred](kotlinx.coroutines.-deferred/index.md) |  |

+ 7 - 0
docs/api/net/com.drake.net.transform/kotlinx.coroutines.-deferred/index.md

@@ -0,0 +1,7 @@
+[net](../../index.md) / [com.drake.net.transform](../index.md) / [kotlinx.coroutines.Deferred](./index.md)
+
+### Extensions for kotlinx.coroutines.Deferred
+
+| Name | Summary |
+|---|---|
+| [transform](transform.md) | `fun <T> Deferred<T>.transform(block: (T) -> T): `[`DeferredTransform`](../-deferred-transform/index.md)`<T>` |

+ 5 - 0
docs/api/net/com.drake.net.transform/kotlinx.coroutines.-deferred/transform.md

@@ -0,0 +1,5 @@
+[net](../../index.md) / [com.drake.net.transform](../index.md) / [kotlinx.coroutines.Deferred](index.md) / [transform](./transform.md)
+
+# transform
+
+`fun <T> Deferred<T>.transform(block: (T) -> T): `[`DeferredTransform`](../-deferred-transform/index.md)`<T>`

+ 1 - 0
docs/api/net/com.drake.net.utils/index.md

@@ -19,6 +19,7 @@
 | [androidx.lifecycle.ViewModelStoreOwner](androidx.lifecycle.-view-model-store-owner/index.md) |  |
 | [com.drake.brv.PageRefreshLayout](com.drake.brv.-page-refresh-layout/index.md) |  |
 | [com.drake.statelayout.StateLayout](com.drake.statelayout.-state-layout/index.md) |  |
+| [kotlinx.coroutines.CoroutineScope](kotlinx.coroutines.-coroutine-scope/index.md) |  |
 | [kotlinx.coroutines.flow.Flow](kotlinx.coroutines.flow.-flow/index.md) |  |
 
 ### Functions

+ 24 - 0
docs/api/net/com.drake.net.utils/kotlinx.coroutines.-coroutine-scope/fastest.md

@@ -0,0 +1,24 @@
+[net](../../index.md) / [com.drake.net.utils](../index.md) / [kotlinx.coroutines.CoroutineScope](index.md) / [fastest](./fastest.md)
+
+# fastest
+
+`suspend fun <T> CoroutineScope.fastest(vararg deferredArray: Deferred<T>): T`
+
+该函数将选择[deferredArray](fastest.md#com.drake.net.utils$fastest(kotlinx.coroutines.CoroutineScope, kotlin.Array((kotlinx.coroutines.Deferred((com.drake.net.utils.fastest.T)))))/deferredArray)中的Deferred执行[Deferred.await](#), 然后将返回最快的结果
+执行过程中的异常将被忽略, 如果全部抛出异常则将抛出最后一个Deferred的异常
+
+### Parameters
+
+`deferredArray` - 一系列并发任务`suspend fun <T> CoroutineScope.fastest(vararg deferredArray: `[`DeferredTransform`](../../com.drake.net.transform/-deferred-transform/index.md)`<T>): T`
+
+该函数将选择[deferredArray](fastest.md#com.drake.net.utils$fastest(kotlinx.coroutines.CoroutineScope, kotlin.Array((com.drake.net.transform.DeferredTransform((com.drake.net.utils.fastest.T)))))/deferredArray)中的Deferred执行[Deferred.await](#), 然后将返回最快的结果
+执行过程中的异常将被忽略, 如果全部抛出异常则将抛出最后一个Deferred的异常
+
+### Parameters
+
+`deferredArray` - 一系列并发任务
+
+**See Also**
+
+[DeferredTransform](../../com.drake.net.transform/-deferred-transform/index.md)
+

+ 7 - 0
docs/api/net/com.drake.net.utils/kotlinx.coroutines.-coroutine-scope/index.md

@@ -0,0 +1,7 @@
+[net](../../index.md) / [com.drake.net.utils](../index.md) / [kotlinx.coroutines.CoroutineScope](./index.md)
+
+### Extensions for kotlinx.coroutines.CoroutineScope
+
+| Name | Summary |
+|---|---|
+| [fastest](fastest.md) | 该函数将选择[deferredArray](fastest.md#com.drake.net.utils$fastest(kotlinx.coroutines.CoroutineScope, kotlin.Array((kotlinx.coroutines.Deferred((com.drake.net.utils.fastest.T)))))/deferredArray)中的Deferred执行[Deferred.await](#), 然后将返回最快的结果 执行过程中的异常将被忽略, 如果全部抛出异常则将抛出最后一个Deferred的异常`suspend fun <T> CoroutineScope.fastest(vararg deferredArray: Deferred<T>): T`<br>`suspend fun <T> CoroutineScope.fastest(vararg deferredArray: `[`DeferredTransform`](../../com.drake.net.transform/-deferred-transform/index.md)`<T>): T` |

+ 1 - 1
docs/api/net/index.md

@@ -5,12 +5,12 @@
 | Name | Summary |
 |---|---|
 | [com.drake.net](com.drake.net/index.md) |  |
-| [com.drake.net.connect](com.drake.net.connect/index.md) |  |
 | [com.drake.net.convert](com.drake.net.convert/index.md) |  |
 | [com.drake.net.error](com.drake.net.error/index.md) |  |
 | [com.drake.net.scope](com.drake.net.scope/index.md) |  |
 | [com.drake.net.tag](com.drake.net.tag/index.md) |  |
 | [com.drake.net.time](com.drake.net.time/index.md) |  |
+| [com.drake.net.transform](com.drake.net.transform/index.md) |  |
 | [com.drake.net.utils](com.drake.net.utils/index.md) |  |
 
 ### Index

+ 4 - 1
docs/api/net/package-list

@@ -18,6 +18,9 @@ $dokka.location:com.drake.net$onError(com.yanzhenjie.kalle.KalleConfig.Builder,
 $dokka.location:com.drake.net$onStateError(com.yanzhenjie.kalle.KalleConfig.Builder, kotlin.Function2((kotlin.Throwable, android.view.View, kotlin.Unit)))com.drake.net/com.yanzhenjie.kalle.-kalle-config.-builder/on-state-error.md
 $dokka.location:com.drake.net$syncDownloadImage(android.content.Context, kotlin.String, kotlin.Int, kotlin.Int)com.drake.net/android.content.-context/sync-download-image.md
 $dokka.location:com.drake.net.error$NetCancellationException(kotlinx.coroutines.CoroutineScope, kotlin.String)com.drake.net.error/kotlinx.coroutines.-coroutine-scope/-net-cancellation-exception.md
+$dokka.location:com.drake.net.transform$transform(kotlinx.coroutines.Deferred((com.drake.net.transform.transform.T)), kotlin.Function1((com.drake.net.transform.transform.T, )))com.drake.net.transform/kotlinx.coroutines.-deferred/transform.md
+$dokka.location:com.drake.net.utils$fastest(kotlinx.coroutines.CoroutineScope, kotlin.Array((com.drake.net.transform.DeferredTransform((com.drake.net.utils.fastest.T)))))com.drake.net.utils/kotlinx.coroutines.-coroutine-scope/fastest.md
+$dokka.location:com.drake.net.utils$fastest(kotlinx.coroutines.CoroutineScope, kotlin.Array((kotlinx.coroutines.Deferred((com.drake.net.utils.fastest.T)))))com.drake.net.utils/kotlinx.coroutines.-coroutine-scope/fastest.md
 $dokka.location:com.drake.net.utils$foreach(android.database.Cursor, kotlin.Function1((android.database.Cursor, kotlin.Unit)))com.drake.net.utils/android.database.-cursor/foreach.md
 $dokka.location:com.drake.net.utils$getSavedModel(androidx.fragment.app.Fragment)com.drake.net.utils/androidx.fragment.app.-fragment/get-saved-model.md
 $dokka.location:com.drake.net.utils$getSavedModel(androidx.fragment.app.FragmentActivity)com.drake.net.utils/androidx.fragment.app.-fragment-activity/get-saved-model.md
@@ -34,10 +37,10 @@ $dokka.location:com.drake.net.utils$scopeLife(androidx.lifecycle.LifecycleOwner,
 $dokka.location:com.drake.net.utils$scopeNetLife(androidx.fragment.app.Fragment, androidx.lifecycle.Lifecycle.Event, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, kotlin.Unit)))com.drake.net.utils/androidx.fragment.app.-fragment/scope-net-life.md
 $dokka.location:com.drake.net.utils$scopeNetLife(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.Event, kotlin.coroutines.SuspendFunction1((kotlinx.coroutines.CoroutineScope, kotlin.Unit)))com.drake.net.utils/androidx.lifecycle.-lifecycle-owner/scope-net-life.md
 com.drake.net
-com.drake.net.connect
 com.drake.net.convert
 com.drake.net.error
 com.drake.net.scope
 com.drake.net.tag
 com.drake.net.time
+com.drake.net.transform
 com.drake.net.utils

+ 0 - 25
docs/fast-select.md

@@ -1,25 +0,0 @@
-Net支持多个接口请求并发, 仅返回最快的请求结果, 剩余请求将被自动取消, 同样可以用于筛选掉无法请求的域名
-<br>
-
-!!! note
-    接口请求错误被忽略(LogCat依然可以看到异常信息), 但如果所有请求全部异常则抛出最后一个请求的异常作为错误处理
-
-示例
-```kotlin
-scopeNetLife {
-
-    // 同时发起四个网络请求
-    val deferred = Get<String>("api0") // 错误接口
-    val deferred1 = Get<String>("api1") // 错误接口
-    val deferred2 = Get<String>("api")
-    val deferred3 = Post<String>("api")
-
-    // 只返回最快的请求结果
-    tv_fragment.text = fastSelect(deferred, deferred1, deferred2, deferred3)
-}
-```
-
-<br>
-
-!!! note
-    不要尝试使用这种方式来取代CDN加速

+ 48 - 0
docs/fastest.md

@@ -0,0 +1,48 @@
+Net支持多个接口请求并发, 仅返回最快的请求结果, 剩余请求将被自动取消, 同样可以用于筛选掉无法请求的域名
+<br>
+
+!!! note
+    接口请求错误被忽略(LogCat依然可以看到异常信息), 但如果所有请求全部异常则抛出最后一个请求的异常作为错误处理
+
+示例
+```kotlin
+scopeNetLife {
+
+    // 同时发起四个网络请求
+    val deferred = Get<String>("api0") // 错误接口
+    val deferred1 = Get<String>("api1") // 错误接口
+    val deferred2 = Get<String>("api")
+    val deferred3 = Post<String>("api")
+
+    // 只返回最快的请求结果
+    tv_fragment.text = fastSelect(deferred, deferred1, deferred2, deferred3)
+}
+```
+
+<br>
+
+假设并发的接口返回的数据类型不同  或者 想要监听最快请求返回的结果回调请使用[transform](api/net/com.drake.net.utils/kotlinx.coroutines.-coroutine-scope/fastest.md)函数
+
+```kotlin
+scopeNetLife {
+
+    val fastest = Post<String>("api").transform {
+        Log.d("日志", "Post") // 如果该接口最快则会回调这里
+        it // 这里可以返回其他数据结果
+    }
+
+    val fastest2 = Get<String>("api").transform {
+        Log.d("日志", "Get") // 如果该接口最快则会回调这里
+        it
+    }
+
+    tv_fragment.text = fastest(fastest, fastest2)
+}
+```
+
+有的场景下并发的接口返回的数据类型不同, 但是fastest只能返回一个类型, 我们可以使`transform`的回调函数返回结果都拥有一个共同的接口, 然后去类型判断
+
+<br>
+
+!!! note
+    不要尝试使用这种方式来取代CDN加速

+ 1 - 2
mkdocs.yml

@@ -52,8 +52,7 @@ nav:
   - 下载文件: download-file.md
   - 下载图片: download-image.md
   - 读取缓存: read-cache.md
-  - 最快选择: fast-select.md
+  - 最快选择: fastest.md
   - 取消请求: cancel.md
   - 轮循器: interval.md
-  #  - 日志: log.md
   - 2.x文档: api/net/index.md

+ 29 - 0
net/src/main/java/com/drake/net/transform/DeferredTransform.kt

@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 Drake, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.drake.net.transform
+
+import kotlinx.coroutines.Deferred
+
+
+fun <T> Deferred<T>.transform(block: (T) -> T): DeferredTransform<T> {
+    return DeferredTransform(this, block)
+}
+
+data class DeferredTransform<T>(
+    val deferred: Deferred<T>,
+    val block: (T) -> T = { it }
+)

+ 39 - 0
net/src/main/java/com/drake/net/utils/ScopeUtils.kt

@@ -23,12 +23,15 @@ import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.LifecycleOwner
 import com.drake.brv.PageRefreshLayout
 import com.drake.net.scope.*
+import com.drake.net.transform.DeferredTransform
 import com.drake.statelayout.StateLayout
 import com.yanzhenjie.kalle.NetCancel
 import kotlinx.coroutines.*
 import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.FlowCollector
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
 
 /**
  * 作用域内部全在主线程
@@ -175,5 +178,41 @@ suspend fun <T> CoroutineScope.fastest(vararg deferredArray: Deferred<T>): T {
     return chan.receive()
 }
 
+/**
+ * 该函数将选择[deferredArray]中的Deferred执行[Deferred.await], 然后将返回最快的结果
+ * 执行过程中的异常将被忽略, 如果全部抛出异常则将抛出最后一个Deferred的异常
+ *
+ * @see DeferredTransform 允许监听[Deferred]返回数据回调
+ * @param deferredArray 一系列并发任务
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+@Suppress("SuspendFunctionOnCoroutineScope")
+suspend fun <T> CoroutineScope.fastest(vararg deferredArray: DeferredTransform<T>): T {
+    val chan = Channel<T>()
+    val mutex = Mutex()
+    deferredArray.forEach {
+        launch(Dispatchers.IO) {
+            try {
+                val result = it.deferred.await()
+                NetCancel.cancel(coroutineContext[CoroutineExceptionHandler])
+                mutex.withLock {
+                    if (!chan.isClosedForSend) {
+                        val transformResult = it.block(result)
+                        chan.send(transformResult)
+                        chan.close()
+                    }
+                }
+            } catch (e: Exception) {
+                it.deferred.cancel()
+                val allFail = deferredArray.all { it.deferred.isCancelled }
+                if (allFail) throw e else e.printStackTrace()
+            } finally {
+                chan.close()
+            }
+        }
+    }
+    return chan.receive()
+}
+
 
 

+ 11 - 7
sample/src/main/java/com/drake/net/sample/ui/fragment/FastSelectFragment.kt → sample/src/main/java/com/drake/net/sample/ui/fragment/FastestFragment.kt

@@ -26,15 +26,14 @@ 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_fast_select.*
+import kotlinx.android.synthetic.main.fragment_fastest.*
 
-class FastSelectFragment : Fragment() {
+class FastestFragment : Fragment() {
 
-    override fun onCreateView(
-        inflater: LayoutInflater, container: ViewGroup?,
-        savedInstanceState: Bundle?
-    ): View? {
-        return inflater.inflate(R.layout.fragment_fast_select, container, false)
+    override fun onCreateView(inflater: LayoutInflater,
+                              container: ViewGroup?,
+                              savedInstanceState: Bundle?): View? {
+        return inflater.inflate(R.layout.fragment_fastest, container, false)
     }
 
     override fun onActivityCreated(savedInstanceState: Bundle?) {
@@ -51,5 +50,10 @@ class FastSelectFragment : Fragment() {
             // 只返回最快的请求结果
             tv_fragment.text = fastest(deferred, deferred1, deferred2, deferred3)
         }
+
+        /*
+        假设并发的接口返回的数据类型不同  或者 想要监听最快请求返回的结果回调请使用 [Deferred.transform] 函数
+        具体请看文档 https://liangjingkanji.github.io/Net/fastest/
+        */
     }
 }

+ 0 - 0
sample/src/main/res/drawable/ic_fast_select.xml → sample/src/main/res/drawable/ic_fastest.xml


+ 1 - 1
sample/src/main/res/layout/fragment_fast_select.xml → sample/src/main/res/layout/fragment_fastest.xml

@@ -18,7 +18,7 @@
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    tools:context=".ui.fragment.FastSelectFragment">
+    tools:context=".ui.fragment.FastestFragment">
 
     <TextView
         android:id="@+id/tv_fragment"

+ 2 - 2
sample/src/main/res/menu/menu_main.xml

@@ -64,8 +64,8 @@
         android:icon="@drawable/ic_read_cache"
         android:title="预读缓存" />
     <item
-        android:id="@+id/fast_select"
-        android:icon="@drawable/ic_fast_select"
+        android:id="@+id/fastest"
+        android:icon="@drawable/ic_fastest"
         android:title="最快选择" />
     <item
         android:id="@+id/state_layout"

+ 5 - 5
sample/src/main/res/navigation/nav_main.xml

@@ -18,7 +18,7 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/main"
-    app:startDestination="@id/request_method">
+    app:startDestination="@id/fastest">
 
     <fragment
         android:id="@+id/async_task"
@@ -112,9 +112,9 @@
         android:label="上传文件"
         tools:layout="@layout/fragment_upload_file" />
     <fragment
-        android:id="@+id/fast_select"
-        android:name="com.drake.net.sample.ui.fragment.FastSelectFragment"
-        android:label="最快选择"
-        tools:layout="@layout/fragment_fast_select" />
+        android:id="@+id/fastest"
+        android:name="com.drake.net.sample.ui.fragment.FastestFragment"
+        android:label="最快请求"
+        tools:layout="@layout/fragment_fastest" />
 
 </navigation>