Browse Source

添加在ViewModel中创建自动处理生命周期的作用域: scopeLife/scopeNetLife

drake 4 years ago
parent
commit
445f1fe007

+ 2 - 0
docs/scope.md

@@ -12,6 +12,7 @@ Net的网络请求本身支持在官方的自带的作用域内使用, 但是考
 |-|-|
 |`scope`|创建最基础的作用域, 所有作用域都包含异常捕捉|
 |`scopeLife`|创建跟随生命周期取消的作用域|
+|`ViewModel.scopeLife`|创建跟随`ViewModel`生命周期的作用域|
 
 
 ## 网络请求的作用域
@@ -25,6 +26,7 @@ Net的网络请求本身支持在官方的自带的作用域内使用, 但是考
 |`scopeNet`|创建自动处理网络错误的作用域|
 |`scopeNetLife`|创建自动处理网络错误的作用域, 且包含跟随Activity或者Fragment生命周期|
 |`scopeDialog`|创建自动加载对话框的作用域, 生命周期跟随对话框|
+|`ViewModel.scopeNetLife`|创建跟随`ViewModel`生命周期的作用域|
 |`PageRefreshLayout.scope`|创建跟随[PageRefreshLayout](https://github.com/liangjingkanji/BRV)生命周期的作用域|
 |`StateLayout.scope`|创建跟随[StateLayout](https://github.com/liangjingkanji/BRV)生命周期的作用域|
 

+ 2 - 2
gradle/wrapper/gradle-wrapper.properties

@@ -1,6 +1,6 @@
-#Thu Oct 29 15:58:06 CST 2020
+#Wed Apr 07 14:55:23 PST 2021
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip

+ 35 - 0
net/src/main/java/androidx/lifecycle/Scope.kt

@@ -0,0 +1,35 @@
+package androidx.lifecycle
+
+import com.drake.net.scope.AndroidScope
+import com.drake.net.scope.NetCoroutineScope
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+
+
+private const val JOB_KEY = "com.drake.net.view-model"
+
+/**
+ * 在[ViewModel]被销毁时取消协程作用域
+ */
+fun ViewModel.scopeLife(
+    dispatcher: CoroutineDispatcher = Dispatchers.Main,
+    block: suspend CoroutineScope.() -> Unit
+): AndroidScope {
+    val scope: AndroidScope? = this.getTag(JOB_KEY)
+    if (scope != null) return scope
+    return setTagIfAbsent(JOB_KEY, AndroidScope(dispatcher = dispatcher).launch(block))
+}
+
+/**
+ * 在[ViewModel]被销毁时取消协程作用域以及其中的网络请求
+ * 具备网络错误全局处理功能, 其内部的网络请求会跟随其作用域的生命周期
+ */
+fun ViewModel.scopeNetLife(
+    dispatcher: CoroutineDispatcher = Dispatchers.Main,
+    block: suspend CoroutineScope.() -> Unit
+): NetCoroutineScope {
+    val scope: NetCoroutineScope? = this.getTag(JOB_KEY)
+    if (scope != null) return scope
+    return setTagIfAbsent(JOB_KEY, NetCoroutineScope(dispatcher = dispatcher).launch(block))
+}

+ 7 - 2
net/src/main/java/com/drake/net/scope/AndroidScope.kt

@@ -21,6 +21,7 @@ import androidx.lifecycle.LifecycleEventObserver
 import androidx.lifecycle.LifecycleOwner
 import com.drake.net.NetConfig
 import kotlinx.coroutines.*
+import java.io.Closeable
 import kotlin.coroutines.CoroutineContext
 import kotlin.coroutines.EmptyCoroutineContext
 
@@ -32,7 +33,7 @@ open class AndroidScope(
     lifecycleOwner: LifecycleOwner? = null,
     lifeEvent: Lifecycle.Event = Lifecycle.Event.ON_DESTROY,
     val dispatcher: CoroutineDispatcher = Dispatchers.Main
-) : CoroutineScope {
+) : CoroutineScope, Closeable {
 
     init {
         lifecycleOwner?.lifecycle?.addObserver(object : LifecycleEventObserver {
@@ -100,7 +101,7 @@ open class AndroidScope(
 
     open fun cancel(cause: CancellationException? = null) {
         val job = coroutineContext[Job]
-                  ?: error("Scope cannot be cancelled because it does not have a job: $this")
+            ?: error("Scope cannot be cancelled because it does not have a job: $this")
         job.cancel(cause)
     }
 
@@ -109,5 +110,9 @@ open class AndroidScope(
         cause: Throwable? = null
     ) = cancel(CancellationException(message, cause))
 
+    override fun close() {
+        cancel()
+    }
+
 }
 

+ 17 - 3
net/src/main/java/com/drake/net/utils/Scope.kt

@@ -28,6 +28,7 @@ import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 
+
 /**
  * 作用域内部全在主线程
  * 作用域全部属于异步
@@ -131,9 +132,11 @@ fun Fragment.scopeLife(
 //</editor-fold>
 
 //<editor-fold desc="网络">
+
 /**
- * 网络请求的异步作用域
- * 自动显示错误信息吐司
+ * 该函数比[scope]多了以下功能
+ * - 在作用域内抛出异常时会被回调的[NetConfig.onError]函数中
+ * - 自动显示错误信息吐司, 可以通过指定[NetConfig.onError]来取消或者增加自己的处理
  *
  * 该作用域生命周期跟随整个应用, 注意内存泄漏
  */
@@ -142,7 +145,14 @@ fun scopeNet(
     block: suspend CoroutineScope.() -> Unit
 ) = NetCoroutineScope(dispatcher = dispatcher).launch(block)
 
-
+/**
+ * 该函数比scopeNet多了自动取消作用域功能
+ *
+ * 该作用域生命周期跟随LifecycleOwner. 比如传入Activity会默认在[FragmentActivity.onDestroy]时取消网络请求.
+ * @receiver 可传入FragmentActivity/AppCompatActivity, 或者其他的实现了LifecycleOwner的类
+ * @param lifeEvent 指定LifecycleOwner处于生命周期下取消网络请求/作用域
+ * @param dispatcher 调度器, 默认运行在[Dispatchers.Main]即主线程下
+ */
 fun LifecycleOwner.scopeNetLife(
     lifeEvent: Lifecycle.Event = Lifecycle.Event.ON_DESTROY,
     dispatcher: CoroutineDispatcher = Dispatchers.Main,
@@ -150,6 +160,8 @@ fun LifecycleOwner.scopeNetLife(
 ) = NetCoroutineScope(this, lifeEvent, dispatcher).launch(block)
 
 /**
+ * 和上述函数功能相同, 只是接受者为Fragment
+ *
  * Fragment应当在[Lifecycle.Event.ON_STOP]时就取消作用域, 避免[Fragment.onDestroyView]导致引用空视图
  */
 fun Fragment.scopeNetLife(
@@ -157,4 +169,6 @@ fun Fragment.scopeNetLife(
     dispatcher: CoroutineDispatcher = Dispatchers.Main,
     block: suspend CoroutineScope.() -> Unit
 ) = NetCoroutineScope(this, lifeEvent, dispatcher).launch(block)
+
+
 //</editor-fold>