Browse Source

- 现在缺省页支持子线程显示
- 增加Observer返回值用于手动取消网络请求
- 现在基本上无需创建Observer匿名对象来使用, 直接使用函数 error {} 就可以自定义错误处理
- 网络请求增加参数tag, 用于在Request中获取传递对象 (例如拦截器中)
- net(this, lifecycle) 支持自定义绑定生命周期
- PageObserver 可以直接使用index属性

drake 5 years ago
parent
commit
d5d7b94021

+ 22 - 2
README.md

@@ -54,7 +54,7 @@ allprojects {
 module 的 build.gradle
 
 ```groovy
-implementation 'com.github.liangjingkanji:Net:1.2.4'
+implementation 'com.github.liangjingkanji:Net:1.2.5'
 ```
 
 
@@ -266,6 +266,10 @@ post<Model>(""){
 
 其他的对话框或者缺省页和下拉刷新等自动支持生命周期管理
 
+Net框架本身的生命周期管理是针对Fragment|Activity的页面销毁时才会自动取消订阅, 如果需要自定义页面生命周期推荐使用我的另外一个库: [AutoDispose](https://github.com/liangjingkanji/AutoDispose)
+
+返回值 Disposable 可以用于完全手动任何位置取消, 
+
 ## 对话框
 
 将会在网络请求开始时弹出对话框, 结束时关闭对话框.
@@ -395,7 +399,7 @@ post<Model>(""){
 
 会根据参数的不同而给不同的对象添加缺省页状态
 
-##重写 Observer
+##Observer
 
 无论是`page/refresh/net/dialog`这些函数本身都是快速创建Observer的扩展函数而已, 如果你需要拿到Observer的onError/onCompleted等回调请自己创建匿名类或者继承.
 
@@ -420,6 +424,22 @@ fun <M> Observable<M>.page(
 
 
 
+扩展函数都会返回对应的Observer对象可以进行手动取消订阅等操作
+
+```kotlin
+val netObserver = download(
+    "https://cdn.sspai.com/article/ebe361e4-c891-3afd-8680-e4bad609723e.jpg?imageMogr2/quality/95/thumbnail/!2880x620r/gravity/Center/crop/2880x620/interlace/1",
+    isAbsolutePath = true
+).net(this) {
+
+}.error {
+    // 自定义自己的错误处理
+    handleError(it) // 该函数每个Observer都存在, 属于默认的错误处理操作
+}
+```
+
+
+
 ## 请求和响应规范
 
 很多时候存在请求和响应的后台接口规范不是常规统一的, 这个时候我们可以自己拦截处理数据. 

+ 1 - 1
net/build.gradle

@@ -41,7 +41,7 @@ dependencies {
     api 'com.yanzhenjie:okalle:0.1.7'
 
     compileOnly 'androidx.appcompat:appcompat:1.1.0'
-    compileOnly 'com.github.liangjingkanji:BRV:1.1.1'
+    compileOnly 'com.github.liangjingkanji:BRV:1.1.2'
     compileOnly 'com.github.bumptech.glide:glide:4.9.0'
 
     compileOnly 'io.reactivex.rxjava2:rxkotlin:2.3.0'

+ 17 - 12
net/src/main/java/com/drake/net/Net.kt

@@ -28,18 +28,20 @@ import java.io.File
  * @param path String 网络路径, 非绝对路径会加上HOST为前缀
  * @see NetConfig.host
  * @param isAbsolutePath Boolean Path是否是绝对路径
+ * @param tag 可以传递对象给Request请求
  * @param block SimpleUrlRequest.Api.() -> UnitUtils
  * @return Observable<M> 结果会在主线程
  */
 inline fun <reified M> get(
     path: String,
+    tag: Any? = null,
     isAbsolutePath: Boolean = false,
     noinline block: (SimpleUrlRequest.Api.() -> Unit)? = null
 ): Observable<M> {
 
     return Observable.create<M> {
         try {
-            val get = Kalle.get(if (isAbsolutePath) path else (NetConfig.host + path))
+            val get = Kalle.get(if (isAbsolutePath) path else (NetConfig.host + path)).tag(tag)
             val response = if (block == null) {
                 get.perform(M::class.java, String::class.java)
             } else {
@@ -69,19 +71,21 @@ inline fun <reified M> get(
  * Post提交
  * @param path String 网络路径, 非绝对路径会加上HOST为前缀
  * @see NetConfig.host
+ * @param tag 可以传递对象给Request请求
  * @param isAbsolutePath Boolean 是否是绝对路径
  * @param block SimpleBodyRequest.Api.() -> UnitUtils
  * @return Observable<M> 结果会在主线程
  */
 inline fun <reified M> post(
     path: String,
+    tag: Any? = null,
     isAbsolutePath: Boolean = false,
     noinline block: (SimpleBodyRequest.Api.() -> Unit)? = null
 ): Observable<M> {
 
     return Observable.create<M> {
         try {
-            val post = Kalle.post(if (isAbsolutePath) path else (NetConfig.host + path))
+            val post = Kalle.post(if (isAbsolutePath) path else (NetConfig.host + path)).tag(tag)
             val response = if (block == null) {
                 post.perform<M, String>(M::class.java, String::class.java)
             } else {
@@ -114,6 +118,7 @@ inline fun <reified M> post(
  * @param path String 网络路径, 非绝对路径会加上HOST为前缀
  * @see NetConfig.host
  * @param directory String 下载文件存放目录 {默认存在android/data/packageName/cache目录}
+ * @param tag 可以传递对象给Request请求
  * @param isAbsolutePath Boolean 下载链接是否是绝对路径
  * @param block 请求参数
  * @return Observable<String> 结果会在主线程
@@ -121,6 +126,7 @@ inline fun <reified M> post(
 fun download(
     path: String,
     directory: String = NetConfig.app.externalCacheDir!!.absolutePath,
+    tag: Any? = null,
     isAbsolutePath: Boolean = false,
     block: (UrlDownload.Api.() -> Unit)? = null
 ): Observable<String> {
@@ -129,7 +135,7 @@ fun download(
         try {
             val realPath = if (isAbsolutePath) path else (NetConfig.host + path)
 
-            val download = Kalle.Download.get(realPath).directory(directory)
+            val download = Kalle.Download.get(realPath).directory(directory).tag(tag)
 
             val filePath = if (block == null) {
                 download.perform()
@@ -180,9 +186,7 @@ fun Context.downloadImg(url: String, with: Int = -1, height: Int = -1): Observab
                 it.onComplete()
             }
         } catch (e: Exception) {
-            if (!it.isDisposed) {
-                it.onError(e)
-            }
+            if (!it.isDisposed) it.onError(e)
         }
 
     }.subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread())
@@ -194,13 +198,14 @@ fun Context.downloadImg(url: String, with: Int = -1, height: Int = -1): Observab
 
 inline fun <reified M> syncGet(
     path: String,
+    tag: Any? = null,
     isAbsolutePath: Boolean = false,
     noinline block: (SimpleUrlRequest.Api.() -> Unit)? = null
 ): Observable<M> {
 
     return Observable.create<M> {
         try {
-            val get = Kalle.get(if (isAbsolutePath) path else (NetConfig.host + path))
+            val get = Kalle.get(if (isAbsolutePath) path else (NetConfig.host + path)).tag(tag)
             val response = if (block == null) {
                 get.perform(M::class.java, String::class.java)
             } else {
@@ -212,9 +217,7 @@ inline fun <reified M> syncGet(
                     it.onNext(response.succeed())
                     it.onComplete()
                 } else {
-                    it.onError(
-                        ResponseException(response.failed(), response.code())
-                    )
+                    it.onError(ResponseException(response.failed(), response.code()))
                 }
             }
         } catch (e: java.lang.Exception) {
@@ -227,13 +230,14 @@ inline fun <reified M> syncGet(
 
 inline fun <reified M> syncPost(
     path: String,
+    tag: Any? = null,
     isAbsolutePath: Boolean = false,
     noinline block: (SimpleBodyRequest.Api.() -> Unit)? = null
 ): Observable<M> {
 
     return Observable.create<M> {
         try {
-            val post = Kalle.post(if (isAbsolutePath) path else (NetConfig.host + path))
+            val post = Kalle.post(if (isAbsolutePath) path else (NetConfig.host + path)).tag(tag)
             val response = if (block == null) {
                 post.perform<M, String>(M::class.java, String::class.java)
             } else {
@@ -261,6 +265,7 @@ inline fun <reified M> syncPost(
 fun syncDownload(
     path: String,
     directory: String = NetConfig.app.externalCacheDir!!.absolutePath,
+    tag: Any? = null,
     isAbsolutePath: Boolean = false,
     block: (UrlDownload.Api.() -> Unit)? = null
 ): Observable<String> {
@@ -269,7 +274,7 @@ fun syncDownload(
         try {
             val realPath = if (isAbsolutePath) path else (NetConfig.host + path)
 
-            val download = Kalle.Download.get(realPath).directory(directory)
+            val download = Kalle.Download.get(realPath).directory(directory).tag(tag)
 
             val filePath = if (block == null) {
                 download.perform()

+ 47 - 33
net/src/main/java/com/drake/net/NetConfig.kt

@@ -5,8 +5,6 @@
  * Date:9/16/19 12:54 AM
  */
 
-@file:Suppress("unused")
-
 package com.drake.net
 
 import android.app.Application
@@ -34,7 +32,6 @@ object NetConfig {
 
     internal var defaultToast: Toast? = null
     internal var defaultDialog: (DialogObserver<*>.(context: FragmentActivity) -> Dialog)? = null
-
     internal var onError: Throwable.() -> Unit = {
 
         val message = when (this) {
@@ -96,47 +93,41 @@ object NetConfig {
 }
 
 
-internal fun Context.toast(message: CharSequence, config: Toast.() -> Unit = {}) {
-    NetConfig.defaultToast?.cancel()
-
-    runMain {
-        NetConfig.defaultToast =
-            Toast.makeText(this, message, Toast.LENGTH_SHORT).apply { config() }
-        NetConfig.defaultToast?.show()
-    }
-}
-
-private fun runMain(block: () -> Unit) {
-    if (Looper.myLooper() == Looper.getMainLooper()) {
-        block()
-    } else {
-        Handler(Looper.getMainLooper()).post { block() }
-    }
-}
-
-
-fun Application.initNet(host: String, block: KalleConfig.Builder.() -> Unit = {}) {
+/**
+ * 初始化框架
+ * @param host 请求url的主机名
+ * @param config 进行配置网络请求
+ *
+ * 如果想要自动解析数据模型请配置转换器, 可以继承或者参考默认转换器
+ * @see DefaultConverter
+ */
+fun Application.initNet(host: String, config: KalleConfig.Builder.() -> Unit = {}) {
     NetConfig.host = host
     NetConfig.app = this
     val builder = KalleConfig.newBuilder()
-    builder.block()
+    builder.config()
     Kalle.setConfig(builder.build())
 }
 
 
 /**
- * 处理错误信息
- * @receiver KalleConfig.Builder
- * @param block [@kotlin.ExtensionFunctionType] Function1<Throwable, Unit>
+ * 该函数指定某些Observer的onError中的默认错误信息处理
+ * @see NetObserver
+ * @see DialogObserver
+ *
+ * @see NetConfig.onError
  */
 fun KalleConfig.Builder.onError(block: Throwable.() -> Unit) {
     NetConfig.onError = block
 }
 
 /**
- * 处理PageObserver的错误信息
- * @receiver KalleConfig.Builder
- * @param block [@kotlin.ExtensionFunctionType] Function2<Throwable, [@kotlin.ParameterName] PageRefreshLayout, Unit>
+ * 该函数指定某些Observer的onError中的默认错误信息处理
+ * @see PageObserver
+ * @see StateObserver
+ *
+ * 如果不设置默认只有 解析数据错误 | 后台自定义错误 会显示吐司
+ * @see NetConfig.onStateError
  */
 fun KalleConfig.Builder.onStateError(block: Throwable.(view: View) -> Unit) {
     NetConfig.onStateError = block
@@ -144,11 +135,34 @@ fun KalleConfig.Builder.onStateError(block: Throwable.(view: View) -> Unit) {
 
 
 /**
- * 设置DialogObserver默认弹出的加载对话框
- * @receiver KalleConfig.Builder
- * @param block [@kotlin.ExtensionFunctionType] Function2<DialogObserver<*>, [@kotlin.ParameterName] FragmentActivity, Dialog>
+ * 设置使用DialogObserver默认弹出的加载对话框
+ * 默认使用系统自带的ProgressDialog
  */
 fun KalleConfig.Builder.onDialog(block: (DialogObserver<*>.(context: FragmentActivity) -> Dialog)) {
     NetConfig.defaultDialog = block
 }
 
+/**
+ * 系统消息吐司
+ * 允许异步线程显示
+ * 不会覆盖显示
+ */
+internal fun Context.toast(message: CharSequence, config: Toast.() -> Unit = {}) {
+    NetConfig.defaultToast?.cancel()
+
+    runMain {
+        NetConfig.defaultToast =
+            Toast.makeText(this, message, Toast.LENGTH_SHORT).apply { config() }
+        NetConfig.defaultToast?.show()
+    }
+}
+
+private fun runMain(block: () -> Unit) {
+    if (Looper.myLooper() == Looper.getMainLooper()) {
+        block()
+    } else {
+        Handler(Looper.getMainLooper()).post { block() }
+    }
+}
+
+

+ 2 - 1
net/src/main/java/com/drake/net/convert/DefaultConverter.kt → net/src/main/java/com/drake/net/convert/JsonConverter.kt

@@ -26,7 +26,7 @@ import java.lang.reflect.Type
  * @property msg String 错误信息的Key名称
  */
 @Suppress("UNCHECKED_CAST")
-abstract class DefaultConverter(
+abstract class JsonConverter(
     val success: String = "0",
     val code: String = "code",
     val msg: String = "msg"
@@ -46,6 +46,7 @@ abstract class DefaultConverter(
         val body = response.body().string()
         var code = response.code()
 
+
         when {
             code in 200..299 -> {
                 val jsonObject = JSONObject(body)

+ 26 - 14
net/src/main/java/com/drake/net/observer/DialogObserver.kt

@@ -18,7 +18,8 @@ import androidx.lifecycle.LifecycleObserver
 import androidx.lifecycle.OnLifecycleEvent
 import com.drake.net.NetConfig
 import com.drake.net.NetConfig.defaultDialog
-import io.reactivex.observers.DefaultObserver
+import com.drake.net.R
+import io.reactivex.observers.DisposableObserver
 
 /**
  * 自动加载对话框网络请求
@@ -29,14 +30,16 @@ import io.reactivex.observers.DefaultObserver
  * 完全: 关闭对话框
  *
  * @param activity 对话框跟随生命周期的FragmentActivity
- * @param dialog 单例对话框
+ * @param dialog 不使用默认的加载对话框而指定对话框
  * @param cancelable 是否允许用户取消对话框
  */
 abstract class DialogObserver<M>(
-    var activity: FragmentActivity?,
+    val activity: FragmentActivity?,
     var dialog: Dialog? = null,
-    var cancelable: Boolean = true
-) : DefaultObserver<M>(), LifecycleObserver {
+    val cancelable: Boolean = true
+) : DisposableObserver<M>(), LifecycleObserver {
+
+    private var error: (DialogObserver<M>.(e: Throwable) -> Unit)? = null
 
     constructor(
         fragment: Fragment?,
@@ -47,45 +50,54 @@ abstract class DialogObserver<M>(
 
     override fun onStart() {
         activity ?: return
-
-        activity!!.lifecycle.addObserver(this)
+        activity.lifecycle.addObserver(this)
 
         dialog = when {
             dialog != null -> dialog
-            defaultDialog != null -> defaultDialog?.invoke(this, activity!!)
+            defaultDialog != null -> defaultDialog?.invoke(this, activity)
             else -> {
                 val progress = ProgressDialog(activity)
-                progress.setMessage("加载中")
+                progress.setMessage(activity.getString(R.string.dialog_msg))
                 progress
             }
         }
 
-        dialog?.setOnDismissListener { cancel() }
+        dialog?.setOnDismissListener { dispose() }
         dialog?.setCancelable(cancelable)
         dialog?.show()
     }
 
     @OnLifecycleEvent(Event.ON_DESTROY)
-    fun dismissDialog() {
+    fun dismiss() {
         if (dialog != null && dialog!!.isShowing) {
-            dialog!!.dismiss()
+            dialog?.dismiss()
         }
     }
 
     abstract override fun onNext(it: M)
 
+    fun error(block: (DialogObserver<M>.(e: Throwable) -> Unit)?): DialogObserver<M> {
+        error = block
+        return this
+    }
+
+
     /**
      * 关闭进度对话框并提醒错误信息
      *
      * @param e 包括错误信息
      */
     override fun onError(e: Throwable) {
-        dismissDialog()
+        dismiss()
+        error?.invoke(this, e) ?: handleError(e)
+    }
+
+    fun handleError(e: Throwable) {
         NetConfig.onError(e)
     }
 
     override fun onComplete() {
-        dismissDialog()
+        dismiss()
     }
 
 }

+ 33 - 12
net/src/main/java/com/drake/net/observer/NetObserver.kt

@@ -7,21 +7,33 @@
 
 package com.drake.net.observer
 
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleObserver
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.OnLifecycleEvent
+import androidx.lifecycle.*
 import com.drake.net.NetConfig
-import io.reactivex.observers.DefaultObserver
+import io.reactivex.observers.DisposableObserver
 
 
 /**
  * 自动显示错误信息
  */
-abstract class NetObserver<M>() : DefaultObserver<M>(), LifecycleObserver {
+abstract class NetObserver<M>() : DisposableObserver<M>(), LifecycleObserver {
 
-    constructor(lifecycleOwner: LifecycleOwner?) : this() {
-        lifecycleOwner?.lifecycle?.addObserver(this)
+    private var error: (NetObserver<M>.(e: Throwable) -> Unit)? = null
+
+    /**
+     * 跟随生命周期
+     * @param lifecycle 默认是销毁时取消订阅
+     */
+    constructor(
+        lifecycleOwner: LifecycleOwner?,
+        lifecycle: Lifecycle.Event = Lifecycle.Event.ON_DESTROY
+    ) : this() {
+        lifecycleOwner?.lifecycle?.addObserver(object : LifecycleEventObserver {
+            override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
+                if (event == lifecycle) {
+                    cancel()
+                }
+            }
+        })
     }
 
     abstract override fun onNext(it: M)
@@ -32,15 +44,24 @@ abstract class NetObserver<M>() : DefaultObserver<M>(), LifecycleObserver {
      * @param e 包括错误信息
      */
     override fun onError(e: Throwable) {
+        error?.invoke(this, e) ?: handleError(e)
+    }
+
+    fun handleError(e: Throwable) {
         NetConfig.onError(e)
     }
 
-    override fun onComplete() {
+    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
+    private fun cancel() {
+        dispose()
+    }
 
+    override fun onComplete() {
     }
 
-    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
-    fun cancelRequest() {
-        cancel()
+    fun error(block: (NetObserver<M>.(e: Throwable) -> Unit)?): NetObserver<M> {
+        error = block
+        return this
     }
+
 }

+ 69 - 45
net/src/main/java/com/drake/net/observer/ObserverUtils.kt

@@ -26,13 +26,14 @@ import io.reactivex.Observable
 fun <M> Observable<M>.net(
     lifecycleOwner: LifecycleOwner? = null,
     block: (NetObserver<M>.(M) -> Unit) = {}
-) {
-
-    subscribe(object : NetObserver<M>(lifecycleOwner) {
-        override fun onNext(t: M) {
-            block(t)
+): NetObserver<M> {
+    val observer = object : NetObserver<M>(lifecycleOwner) {
+        override fun onNext(it: M) {
+            block(it)
         }
-    })
+    }
+    subscribe(observer)
+    return observer
 }
 
 /**
@@ -41,34 +42,49 @@ fun <M> Observable<M>.net(
  * @param stateLayout StateLayout
  * @param block (M) -> UnitUtils
  */
-fun <M> Observable<M>.state(stateLayout: StateLayout, block: StateObserver<M>.(M) -> Unit = {}) {
-    subscribe(object : StateObserver<M>(stateLayout) {
-        override fun onNext(t: M) {
-            block(t)
+fun <M> Observable<M>.state(
+    stateLayout: StateLayout,
+    block: StateObserver<M>.(M) -> Unit = {}
+): StateObserver<M> {
+    val observer = object : StateObserver<M>(stateLayout) {
+        override fun onNext(it: M) {
+            block(it)
         }
-    })
+    }
+    subscribe(observer)
+    return observer
 }
 
-fun <M> Observable<M>.state(view: View, block: StateObserver<M>.(M) -> Unit = {}) {
-    subscribe(object : StateObserver<M>(view) {
-        override fun onNext(t: M) {
-            block(t)
+fun <M> Observable<M>.state(
+    view: View,
+    block: StateObserver<M>.(M) -> Unit = {}
+): StateObserver<M> {
+    val observer = object : StateObserver<M>(view) {
+        override fun onNext(it: M) {
+            block(it)
         }
-    })
+    }
+    subscribe(observer)
+    return observer
 }
 
-fun <M> Observable<M>.state(activity: FragmentActivity, block: StateObserver<M>.(M) -> Unit) {
-    subscribe(object : StateObserver<M>(activity) {
-        override fun onNext(t: M) {
-            block(t)
+fun <M> Observable<M>.state(
+    activity: FragmentActivity,
+    block: StateObserver<M>.(M) -> Unit
+): StateObserver<M> {
+    val observer = object : StateObserver<M>(activity) {
+        override fun onNext(it: M) {
+            block(it)
         }
-    })
+    }
+    subscribe(observer)
+    return observer
 }
 
 fun <M> Observable<M>.state(fragment: Fragment, block: StateObserver<M>.(M) -> Unit = {}) {
     subscribe(object : StateObserver<M>(fragment) {
-        override fun onNext(t: M) {
-            block(t)
+        override fun onNext(it: M) {
+            block(it)
         }
     })
 }
@@ -85,12 +101,14 @@ fun <M> Observable<M>.dialog(
     dialog: Dialog? = null,
     cancelable: Boolean = true,
     block: (DialogObserver<M>.(M) -> Unit) = {}
-) {
-    subscribe(object : DialogObserver<M>(activity, dialog, cancelable) {
-        override fun onNext(t: M) {
-            block(t)
+): DialogObserver<M> {
+    val observer = object : DialogObserver<M>(activity, dialog, cancelable) {
+        override fun onNext(it: M) {
+            block(it)
         }
-    })
+    }
+    subscribe(observer)
+    return observer
 }
 
 
@@ -99,31 +117,35 @@ fun <M> Observable<M>.dialog(
     dialog: Dialog? = null,
     cancelable: Boolean = true,
     block: (DialogObserver<M>.(M) -> Unit) = {}
-) {
-    subscribe(object : DialogObserver<M>(fragment, dialog, cancelable) {
-        override fun onNext(t: M) {
-            block(t)
+): DialogObserver<M> {
+    val observer = object : DialogObserver<M>(fragment, dialog, cancelable) {
+        override fun onNext(it: M) {
+            block(it)
         }
-    })
+    }
+    subscribe(observer)
+    return observer
 }
 
 /**
  * 自动结束下拉加载
  * @receiver Observable<M>
- * @param pageRefreshLayout SmartRefreshLayout
+ * @param refreshLayout SmartRefreshLayout
  * @param loadMore 是否启用上拉加载
  * @param block (M) -> UnitUtils
  */
 fun <M> Observable<M>.refresh(
-    pageRefreshLayout: PageRefreshLayout,
+    refreshLayout: PageRefreshLayout,
     loadMore: Boolean = false,
     block: RefreshObserver<M>.(M) -> Unit = {}
-) {
-    subscribe(object : RefreshObserver<M>(pageRefreshLayout, loadMore) {
-        override fun onNext(t: M) {
-            block(t)
+): RefreshObserver<M> {
+    val observer = object : RefreshObserver<M>(refreshLayout, loadMore) {
+        override fun onNext(it: M) {
+            block(it)
         }
-    })
+    }
+    subscribe(observer)
+    return observer
 }
 
 /**
@@ -136,10 +158,12 @@ fun <M> Observable<M>.refresh(
 fun <M> Observable<M>.page(
     pageRefreshLayout: PageRefreshLayout,
     block: PageObserver<M>.(M) -> Unit = {}
-) {
-    subscribe(object : PageObserver<M>(pageRefreshLayout) {
-        override fun onNext(t: M) {
-            block(t)
+): PageObserver<M> {
+    val observer = object : PageObserver<M>(pageRefreshLayout) {
+        override fun onNext(it: M) {
+            block(it)
         }
-    })
+    }
+    subscribe(observer)
+    return observer
 }

+ 34 - 9
net/src/main/java/com/drake/net/observer/PageObserver.kt

@@ -12,14 +12,21 @@ import android.view.View.OnAttachStateChangeListener
 import com.drake.brv.BindingAdapter
 import com.drake.brv.PageRefreshLayout
 import com.drake.net.NetConfig.onStateError
-import io.reactivex.observers.DefaultObserver
+import com.scwang.smart.refresh.layout.constant.RefreshState
+import io.reactivex.observers.DisposableObserver
 
 /**
  * 自动结束下拉刷新和上拉加载状态
  * 自动展示缺省页
  * 自动分页加载
  */
-abstract class PageObserver<M>(val page: PageRefreshLayout) : DefaultObserver<M>() {
+abstract class PageObserver<M>(val page: PageRefreshLayout) : DisposableObserver<M>() {
+
+
+    val index
+        get() = page.index
+
+    private var error: (PageObserver<M>.(e: Throwable) -> Unit)? = null
 
     init {
         page.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
@@ -28,7 +35,7 @@ abstract class PageObserver<M>(val page: PageRefreshLayout) : DefaultObserver<M>
             }
 
             override fun onViewDetachedFromWindow(v: View) {
-                cancel()
+                dispose()
             }
         })
     }
@@ -37,35 +44,53 @@ abstract class PageObserver<M>(val page: PageRefreshLayout) : DefaultObserver<M>
 
     /**
      * 关闭进度对话框并提醒错误信息
-     *
-     * @param e 包括错误信息
      */
     override fun onError(e: Throwable) {
-        page.showError()
+        if (page.state == RefreshState.Refreshing) {
+            page.showError()
+        } else page.finish(false)
+        error?.invoke(this, e) ?: handleError(e)
+    }
+
+    fun handleError(e: Throwable) {
         onStateError.invoke(e, page)
     }
 
-    override fun onComplete() {
+    fun error(block: (PageObserver<M>.(e: Throwable) -> Unit)?): PageObserver<M> {
+        error = block
+        return this
     }
 
     /**
      * 自动判断是添加数据还是覆盖数据
-     *
-     * @param data 要添加的数据集
      */
     fun addData(data: List<Any>, hasMore: BindingAdapter.() -> Boolean) {
         page.addData(data, hasMore)
     }
 
 
+    /**
+     * 显示空缺省页
+     * 此操作会导致观察者取消订阅
+     */
     fun showEmpty() {
         page.showEmpty()
     }
 
+    override fun onComplete() {
+    }
+
+    /**
+     * 显示内容缺省页
+     */
     fun showContent() {
         page.showContent()
     }
 
+    /**
+     * 结束刷新或者加载
+     * @param success 是否成功
+     */
     fun finish(success: Boolean = true) {
         page.finish(success)
     }

+ 13 - 3
net/src/main/java/com/drake/net/observer/RefreshObserver.kt

@@ -11,7 +11,7 @@ import android.view.View
 import android.view.View.OnAttachStateChangeListener
 import com.drake.net.NetConfig
 import com.scwang.smart.refresh.layout.SmartRefreshLayout
-import io.reactivex.observers.DefaultObserver
+import io.reactivex.observers.DisposableObserver
 
 /**
  * 自动结束下拉刷新
@@ -19,8 +19,9 @@ import io.reactivex.observers.DefaultObserver
 abstract class RefreshObserver<M>(
     val refresh: SmartRefreshLayout,
     val loadMore: Boolean = false
-) : DefaultObserver<M>() {
+) : DisposableObserver<M>() {
 
+    private var error: (RefreshObserver<M>.(e: Throwable) -> Unit)? = null
 
     init {
         refresh.setEnableLoadMore(loadMore)
@@ -30,7 +31,7 @@ abstract class RefreshObserver<M>(
             }
 
             override fun onViewDetachedFromWindow(v: View) {
-                cancel()
+                dispose()
             }
         })
     }
@@ -39,10 +40,19 @@ abstract class RefreshObserver<M>(
 
     override fun onError(e: Throwable) {
         refresh.finishRefresh(false)
+        error?.invoke(this, e) ?: handleError(e)
+    }
+
+    fun handleError(e: Throwable) {
         NetConfig.onError(e)
     }
 
     override fun onComplete() {
         refresh.finishRefresh(true)
     }
+
+    fun error(block: (RefreshObserver<M>.(e: Throwable) -> Unit)?): RefreshObserver<M> {
+        error = block
+        return this
+    }
 }

+ 33 - 18
net/src/main/java/com/drake/net/observer/StateObserver.kt

@@ -14,44 +14,41 @@ import androidx.fragment.app.Fragment
 import com.drake.net.NetConfig
 import com.drake.statelayout.StateLayout
 import com.drake.statelayout.state
-import io.reactivex.observers.DefaultObserver
+import io.reactivex.observers.DisposableObserver
 
 /**
  * 自动显示多状态布局
  */
-abstract class StateObserver<M> : DefaultObserver<M> {
+abstract class StateObserver<M> : DisposableObserver<M> {
 
-    var stateLayout: StateLayout
+    val state: StateLayout
+
+    private var error: (StateObserver<M>.(e: Throwable) -> Unit)? = null
 
     constructor(view: View) {
-        stateLayout = view.state()
+        state = view.state()
     }
 
     constructor(activity: Activity) {
-        stateLayout = activity.state()
+        state = activity.state()
     }
 
     constructor(fragment: Fragment) {
-        stateLayout = fragment.state()
+        state = fragment.state()
     }
 
     constructor(stateLayout: StateLayout) {
-        this.stateLayout = stateLayout
-    }
-
-    fun showEmpty() {
-        stateLayout.showEmpty()
-        cancel()
+        this.state = stateLayout
     }
 
     public override fun onStart() {
-        stateLayout.showLoading()
-        stateLayout.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
+        state.showLoading()
+        state.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
             override fun onViewAttachedToWindow(v: View?) {
             }
 
             override fun onViewDetachedFromWindow(v: View) {
-                cancel()
+                dispose()
             }
         })
     }
@@ -59,11 +56,29 @@ abstract class StateObserver<M> : DefaultObserver<M> {
     abstract override fun onNext(it: M)
 
     override fun onError(e: Throwable) {
-        stateLayout.showError()
-        NetConfig.onStateError(e, stateLayout)
+        state.showError()
+        error?.invoke(this, e) ?: handleError(e)
+    }
+
+    fun handleError(e: Throwable) {
+        NetConfig.onStateError(e, state)
+    }
+
+    fun error(block: (StateObserver<M>.(e: Throwable) -> Unit)?): StateObserver<M> {
+        error = block
+        return this
     }
 
     override fun onComplete() {
-        stateLayout.showContent()
+        state.showContent()
+    }
+
+    /**
+     * 显示空缺省页
+     * 此操作会导致观察者取消订阅
+     */
+    fun showEmpty() {
+        state.showEmpty()
+        dispose()
     }
 }

+ 2 - 0
net/src/main/res/values/strings.xml

@@ -19,5 +19,7 @@
     <string name="image_error">图片下载错误</string>
     <string name="other_error">服务器未响应</string>
 
+    <!--对话框-->
+    <string name="dialog_msg">加载中</string>
 
 </resources>

+ 3 - 1
sample/build.gradle

@@ -38,11 +38,13 @@ dependencies {
 
     implementation 'com.squareup.moshi:moshi-kotlin:1.8.0'
     kapt 'com.squareup.moshi:moshi-kotlin-codegen:1.8.0'
-    implementation 'com.github.liangjingkanji:BRV:1.1.1'
+    implementation 'com.github.liangjingkanji:BRV:1.1.2'
     implementation  'com.scwang.smart:refresh-header-classics:2.0.0-alpha-1'
     implementation  'com.scwang.smart:refresh-footer-classics:2.0.0-alpha-1'
     implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
     implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
 
+    implementation 'com.github.liangjingkanji:debugkit:1.2.9'
+
     implementation 'com.github.bumptech.glide:glide:4.9.0'
 }

+ 2 - 5
sample/src/main/java/com/drake/net/sample/App.kt

@@ -1,13 +1,10 @@
 package com.drake.net.sample
 
 import android.app.Application
-import com.drake.net.convert.DefaultConverter
 import com.drake.net.initNet
 import com.scwang.smart.refresh.footer.ClassicsFooter
 import com.scwang.smart.refresh.header.ClassicsHeader
 import com.scwang.smart.refresh.layout.SmartRefreshLayout
-import com.squareup.moshi.Moshi
-import java.lang.reflect.Type
 
 class App : Application() {
 
@@ -15,11 +12,11 @@ class App : Application() {
         super.onCreate()
 
         initNet("http://localhost.com") {
-            converter(object : DefaultConverter() {
+            /*converter(object : JsonConverter() {
                 override fun <S> convert(succeed: Type, body: String): S? {
                     return Moshi.Builder().build().adapter<S>(succeed).fromJson(body)
                 }
-            })
+            })*/
         }
 
         SmartRefreshLayout.setDefaultRefreshHeaderCreator { context, layout -> ClassicsHeader(this) }

+ 15 - 6
sample/src/main/java/com/drake/net/sample/MainActivity.kt

@@ -1,9 +1,10 @@
 package com.drake.net.sample
 
 import android.os.Bundle
+import android.util.Log
 import androidx.appcompat.app.AppCompatActivity
-import com.drake.net.downloadImg
-import com.drake.net.observer.dialog
+import com.drake.net.download
+import com.drake.net.observer.net
 
 class MainActivity : AppCompatActivity() {
 
@@ -12,10 +13,18 @@ class MainActivity : AppCompatActivity() {
         setContentView(R.layout.activity_main)
 
 
-        downloadImg("static-mobile.xbzhaopin.com/xy00000/images_fh/upload/2019/04/1555745799934.png").dialog(
-            this
-        ) {
-
+        val netObserver = download(
+            "https://cdn.sspai.com/article/ebe361e4-c891-3afd-8680-e4bad609723e.jpg?imageMogr2/quality/95/thumbnail/!2880x620r/gravity/Center/crop/2880x620/interlace/1",
+            isAbsolutePath = true
+        ).net(this) {
+            Log.d("日志", "(MainActivity.kt:22)    下载文件路径 = $it")
+        }.error {
+            Log.d("日志", "(MainActivity.kt:24)    fuck error")
+            handleError(it)
         }
+
+
+        // netObserver.dispose() // 立刻取消
+
     }
 }