|
|
@@ -0,0 +1,330 @@
|
|
|
+# NetworkRx 模块
|
|
|
+
|
|
|
+基于 RxJava 的网络模块封装,参考 MVVMHabit 框架设计,提供完整的网络请求解决方案。
|
|
|
+
|
|
|
+## 功能特点
|
|
|
+
|
|
|
+### 核心功能
|
|
|
+- **网络管理器**:统一的 OkHttpClient 和 Retrofit 配置
|
|
|
+- **拦截器**:请求头拦截器和 Token 自动刷新拦截器
|
|
|
+- **响应封装**:统一的 API 响应格式处理
|
|
|
+- **线程调度**:自动的线程切换(IO 线程执行,主线程回调)
|
|
|
+- **错误处理**:统一的异常处理机制
|
|
|
+- **重试机制**:支持网络请求重试
|
|
|
+- **Token 管理**:自动处理 Token 过期刷新
|
|
|
+- **Cookie 管理**:支持内存和持久化 Cookie 存储
|
|
|
+- **下载管理**:支持文件下载和进度监听
|
|
|
+- **网络状态检测**:支持网络连接状态和类型检测
|
|
|
+
|
|
|
+### 技术栈
|
|
|
+- Kotlin
|
|
|
+- RxJava 2
|
|
|
+- Retrofit 2
|
|
|
+- OkHttp 3
|
|
|
+- Gson
|
|
|
+
|
|
|
+## 目录结构
|
|
|
+
|
|
|
+```
|
|
|
+networkrx/
|
|
|
+├── cookie/ # Cookie 管理
|
|
|
+│ ├── CookieJarImpl.kt # CookieJar 实现
|
|
|
+│ ├── CookieStore.kt # Cookie 存储接口
|
|
|
+│ ├── MemoryCookieStore.kt # 内存 Cookie 存储
|
|
|
+│ └── SPCookieStore.kt # SharedPreferences Cookie 存储
|
|
|
+├── download/ # 下载管理
|
|
|
+│ └── DownloadManager.kt # 下载管理器
|
|
|
+├── interceptor/ # 拦截器
|
|
|
+│ ├── HeaderInterceptor.kt # 请求头拦截器
|
|
|
+│ └── TokenRefreshInterceptor.kt # Token 刷新拦截器
|
|
|
+├── NetworkManager.kt # 网络管理器(核心)
|
|
|
+├── NetworkUtil.kt # 网络工具类
|
|
|
+├── ResponseThrowable.kt # 响应异常类
|
|
|
+├── RxApiResponse.kt # API 响应封装
|
|
|
+├── RxApiResponseTransformer.kt # 响应转换器
|
|
|
+├── RxExceptionHandler.kt # 异常处理器
|
|
|
+├── ApiDisposableObserver.kt # API 可disposable 观察者
|
|
|
+├── README.md # 说明文档
|
|
|
+├── MVVMHABIT对比分析.md # 对比分析文档
|
|
|
+└── MVVMHABIT完整功能实现.md # 完整功能实现说明
|
|
|
+```
|
|
|
+
|
|
|
+## 使用方式
|
|
|
+
|
|
|
+### 1. 基本使用
|
|
|
+
|
|
|
+```kotlin
|
|
|
+// 1. 定义API接口
|
|
|
+interface ApiService {
|
|
|
+ @POST("/api/login")
|
|
|
+ fun login(@Body request: LoginRequest): Observable<LoginResponse>
|
|
|
+
|
|
|
+ @GET("/api/user/profile")
|
|
|
+ fun getUserProfile(): Observable<RxCommonResponse<UserProfile>>
|
|
|
+}
|
|
|
+
|
|
|
+// 2. 创建API服务实例
|
|
|
+val apiService = NetworkManager.createApi(ApiService::class.java)
|
|
|
+
|
|
|
+// 3. 发起网络请求
|
|
|
+apiService.login(LoginRequest("username", "password"))
|
|
|
+ .compose(RxApiResponseTransformer.transform())
|
|
|
+ .subscribe(object : ApiDisposableObserver<LoginResponse>() {
|
|
|
+ override fun onSuccess(data: LoginResponse) {
|
|
|
+ // 处理成功
|
|
|
+ Log.d("Login", "Success: $data")
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun onError(code: Int, message: String) {
|
|
|
+ // 处理错误
|
|
|
+ Log.e("Login", "Error: $code - $message")
|
|
|
+ }
|
|
|
+ })
|
|
|
+```
|
|
|
+
|
|
|
+### 2. 使用通用响应格式
|
|
|
+
|
|
|
+```kotlin
|
|
|
+apiService.getUserProfile()
|
|
|
+ .compose(RxApiResponseTransformer.transformCommonResponse())
|
|
|
+ .subscribe(object : ApiDisposableObserver<UserProfile>() {
|
|
|
+ override fun onSuccess(data: UserProfile) {
|
|
|
+ // 处理成功
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun onError(code: Int, message: String) {
|
|
|
+ // 处理错误
|
|
|
+ }
|
|
|
+ })
|
|
|
+```
|
|
|
+
|
|
|
+### 3. 带重试的请求
|
|
|
+
|
|
|
+```kotlin
|
|
|
+apiService.login(LoginRequest("username", "password"))
|
|
|
+ .compose(RxApiResponseTransformer.transformWithRetry(
|
|
|
+ maxRetries = 3, // 最大重试3次
|
|
|
+ retryDelayMillis = 1000 // 重试延迟1秒
|
|
|
+ ))
|
|
|
+ .subscribe(object : ApiDisposableObserver<LoginResponse>() {
|
|
|
+ override fun onSuccess(data: LoginResponse) {
|
|
|
+ // 处理成功
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun onError(code: Int, message: String) {
|
|
|
+ // 处理错误
|
|
|
+ }
|
|
|
+ })
|
|
|
+```
|
|
|
+
|
|
|
+### 4. 自定义网络配置
|
|
|
+
|
|
|
+```kotlin
|
|
|
+// 自定义OkHttpClient
|
|
|
+val customClient = NetworkManager.createOkHttpClient(
|
|
|
+ HeaderInterceptor(),
|
|
|
+ TokenRefreshInterceptor(),
|
|
|
+ // 可以添加其他自定义拦截器
|
|
|
+ HttpLoggingInterceptor().apply {
|
|
|
+ level = HttpLoggingInterceptor.Level.BODY
|
|
|
+ }
|
|
|
+)
|
|
|
+
|
|
|
+// 创建API服务
|
|
|
+val apiService = NetworkManager.createApi(
|
|
|
+ ApiService::class.java,
|
|
|
+ baseUrl = "https://api.example.com/",
|
|
|
+ client = customClient
|
|
|
+)
|
|
|
+```
|
|
|
+
|
|
|
+### 5. 简单回调方式
|
|
|
+
|
|
|
+```kotlin
|
|
|
+apiService.login(LoginRequest("username", "password"))
|
|
|
+ .compose(RxApiResponseTransformer.transform())
|
|
|
+ .subscribe(SimpleApiDisposableObserver(
|
|
|
+ onSuccess = { data ->
|
|
|
+ // 处理成功
|
|
|
+ },
|
|
|
+ onError = { code, message ->
|
|
|
+ // 处理错误
|
|
|
+ }
|
|
|
+ ))
|
|
|
+```
|
|
|
+
|
|
|
+## 配置说明
|
|
|
+
|
|
|
+### 基础配置
|
|
|
+- **默认超时时间**:30秒
|
|
|
+- **默认BaseUrl**:https://api.example.com/
|
|
|
+- **默认线程调度**:IO线程执行,主线程回调
|
|
|
+
|
|
|
+### 拦截器配置
|
|
|
+
|
|
|
+#### HeaderInterceptor
|
|
|
+自动添加以下请求头:
|
|
|
+- Content-Type: application/json; charset=utf-8
|
|
|
+- Accept: application/json
|
|
|
+- X-App-Version: App版本号
|
|
|
+- X-Device-Type: Android
|
|
|
+- X-Platform: Android
|
|
|
+- X-Request-Id: 唯一请求ID
|
|
|
+- Authorization: Bearer Token(如果存在)
|
|
|
+
|
|
|
+#### TokenRefreshInterceptor
|
|
|
+- 检测401错误(Token过期)
|
|
|
+- 自动刷新Token
|
|
|
+- 线程安全处理(避免并发刷新)
|
|
|
+- 重试失败的请求
|
|
|
+
|
|
|
+## 响应格式
|
|
|
+
|
|
|
+### RxApiResponse
|
|
|
+
|
|
|
+```kotlin
|
|
|
+sealed class RxApiResponse<out T> {
|
|
|
+ data class Success<T>(val data: T) : RxApiResponse<T>()
|
|
|
+ data class Error<T>(
|
|
|
+ val code: Int,
|
|
|
+ val message: String,
|
|
|
+ val error: Throwable? = null
|
|
|
+ ) : RxApiResponse<T>()
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 通用响应格式
|
|
|
+
|
|
|
+```kotlin
|
|
|
+data class RxCommonResponse<T>(
|
|
|
+ val code: Int, // 业务状态码,0表示成功
|
|
|
+ val message: String, // 响应消息
|
|
|
+ val data: T? // 响应数据
|
|
|
+)
|
|
|
+```
|
|
|
+
|
|
|
+## 异常处理
|
|
|
+
|
|
|
+### 网络异常类型
|
|
|
+
|
|
|
+```kotlin
|
|
|
+enum class NetworkErrorType {
|
|
|
+ NETWORK_ERROR, // 网络错误(超时、连接失败等)
|
|
|
+ SERVER_ERROR, // 服务器错误(500系列)
|
|
|
+ TOKEN_EXPIRED, // Token过期(401)
|
|
|
+ BUSINESS_ERROR, // 业务错误(其他HTTP错误)
|
|
|
+ UNKNOWN_ERROR // 未知错误
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 异常处理器
|
|
|
+
|
|
|
+```kotlin
|
|
|
+// 处理异常
|
|
|
+val (code, message) = RxExceptionHandler.handleException(throwable)
|
|
|
+
|
|
|
+// 获取错误类型
|
|
|
+val errorType = RxExceptionHandler.getErrorType(throwable)
|
|
|
+```
|
|
|
+
|
|
|
+## 依赖说明
|
|
|
+
|
|
|
+需要在项目的 build.gradle 中添加以下依赖:
|
|
|
+
|
|
|
+```groovy
|
|
|
+dependencies {
|
|
|
+ // RxJava
|
|
|
+ implementation "io.reactivex.rxjava2:rxjava:2.2.21"
|
|
|
+ implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
|
|
|
+
|
|
|
+ // Retrofit
|
|
|
+ implementation "com.squareup.retrofit2:retrofit:2.9.0"
|
|
|
+ implementation "com.squareup.retrofit2:converter-gson:2.9.0"
|
|
|
+ implementation "com.squareup.retrofit2:adapter-rxjava2:2.9.0"
|
|
|
+
|
|
|
+ // OkHttp
|
|
|
+ implementation "com.squareup.okhttp3:okhttp:4.9.3"
|
|
|
+ implementation "com.squareup.okhttp3:logging-interceptor:4.9.3"
|
|
|
+
|
|
|
+ // Gson
|
|
|
+ implementation "com.google.code.gson:gson:2.8.9"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## 注意事项
|
|
|
+
|
|
|
+1. **Token管理**:需要实现 `TokenRefreshInterceptor` 中的 `refreshToken()` 和 `saveToken()` 方法
|
|
|
+2. **BaseUrl配置**:需要根据实际项目修改 `NetworkManager` 中的 `BASE_URL`
|
|
|
+3. **错误码处理**:需要根据后端返回的错误码格式调整错误处理逻辑
|
|
|
+4. **线程安全**:`TokenRefreshInterceptor` 已做线程安全处理,但在多线程环境下仍需注意
|
|
|
+5. **内存泄漏**:使用 `ApiDisposableObserver` 时,需要注意在适当的时机取消订阅
|
|
|
+6. **Cookie管理**:默认使用内存 Cookie 存储(应用重启后丢失)
|
|
|
+7. **权限**:下载功能需要存储权限,网络状态检测需要网络权限
|
|
|
+
|
|
|
+## 示例代码
|
|
|
+
|
|
|
+### 完整的登录请求示例
|
|
|
+
|
|
|
+```kotlin
|
|
|
+// 1. 定义API接口
|
|
|
+interface AuthApi {
|
|
|
+ @POST("/api/auth/login")
|
|
|
+ fun login(@Body request: LoginRequest): Observable<RxCommonResponse<LoginResponse>>
|
|
|
+}
|
|
|
+
|
|
|
+// 2. 创建API服务
|
|
|
+val authApi = NetworkManager.createApi(AuthApi::class.java)
|
|
|
+
|
|
|
+// 3. 发起登录请求
|
|
|
+val loginDisposable = authApi.login(LoginRequest("user@example.com", "password123"))
|
|
|
+ .compose(RxApiResponseTransformer.transformCommonResponse())
|
|
|
+ .subscribe(object : ApiDisposableObserver<LoginResponse>() {
|
|
|
+ override fun onSuccess(data: LoginResponse) {
|
|
|
+ // 登录成功,保存Token
|
|
|
+ saveToken(data.token)
|
|
|
+
|
|
|
+ // 跳转到主页面
|
|
|
+ navigateToMainActivity()
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun onError(code: Int, message: String) {
|
|
|
+ // 登录失败,显示错误信息
|
|
|
+ showToast(message)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+// 4. 在适当的时机取消订阅
|
|
|
+fun onDestroy() {
|
|
|
+ loginDisposable.dispose()
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## 与 Network 模块对比
|
|
|
+
|
|
|
+| 特性 | NetworkRx | Network(协程) |
|
|
|
+|------|-----------|----------------|
|
|
|
+| 响应式编程 | RxJava 2 | 协程 + Flow |
|
|
|
+| 线程调度 | Schedulers | 协程上下文 |
|
|
|
+| 错误处理 | onError回调 | try-catch |
|
|
|
+| 操作符 | 丰富的Rx操作符 | 协程挂起函数 |
|
|
|
+| 学习成本 | 较高 | 较低 |
|
|
|
+| 代码复杂度 | 中等 | 低 |
|
|
|
+| 生态成熟度 | 成熟稳定 | 现代推荐 |
|
|
|
+
|
|
|
+## 适用场景
|
|
|
+
|
|
|
+- 项目已经使用 RxJava
|
|
|
+- 需要丰富的响应式操作符
|
|
|
+- 习惯使用 Observer 模式
|
|
|
+- 从 MVVMHabit 框架迁移
|
|
|
+
|
|
|
+## 总结
|
|
|
+
|
|
|
+NetworkRx 模块提供了完整的基于 RxJava 的网络请求解决方案,参考 MVVMHabit 框架设计,具有以下优势:
|
|
|
+
|
|
|
+- **功能完整**:涵盖了网络请求的各个方面
|
|
|
+- **使用简单**:链式调用,API 简洁明了
|
|
|
+- **扩展性强**:模块化设计,易于定制
|
|
|
+- **稳定性高**:基于成熟的 RxJava 生态
|
|
|
+
|
|
|
+可以根据项目需求选择使用 NetworkRx(RxJava)或 Network(协程)模块。
|