a
This commit is contained in:
@@ -0,0 +1 @@
|
||||
/build
|
||||
@@ -0,0 +1,34 @@
|
||||
plugins {
|
||||
id 'com.android.library'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk 32
|
||||
|
||||
defaultConfig {
|
||||
minSdk 29
|
||||
targetSdk 32
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.5.0'
|
||||
implementation 'com.google.android.material:material:1.6.1'
|
||||
api("io.github.jeremyliao:live-event-bus-x:1.8.0")
|
||||
api("com.google.code.gson:gson:2.8.6")
|
||||
api("com.squareup.okhttp3:okhttp:4.1.0")
|
||||
api("com.squareup.retrofit2:retrofit:2.9.0")
|
||||
api("com.squareup.retrofit2:converter-gson:2.9.0")
|
||||
api("com.squareup.okhttp3:logging-interceptor:4.9.0")
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.aisier.network">
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.aisier.network
|
||||
|
||||
import com.aisier.network.entity.*
|
||||
|
||||
fun <T> ApiResponse<T>.parseData(listenerBuilder: ResultBuilder<T>.() -> Unit) {
|
||||
val listener = ResultBuilder<T>().also(listenerBuilder)
|
||||
when (this) {
|
||||
is ApiSuccessResponse -> listener.onSuccess(this.response)
|
||||
is ApiEmptyResponse -> listener.onDataEmpty()
|
||||
is ApiFailedResponse -> listener.onFailed(this.errorCode, this.errorMsg)
|
||||
is ApiErrorResponse -> listener.onError(this.throwable)
|
||||
}
|
||||
listener.onComplete()
|
||||
}
|
||||
|
||||
class ResultBuilder<T> {
|
||||
var onSuccess: (data: T?) -> Unit = {}
|
||||
var onDataEmpty: () -> Unit = {}
|
||||
var onFailed: (errorCode: Int?, errorMsg: String?) -> Unit = { _, errorMsg ->
|
||||
errorMsg?.let { toast(it) }
|
||||
}
|
||||
var onError: (e: Throwable) -> Unit = { e ->
|
||||
e.message?.let { toast(it) }
|
||||
}
|
||||
var onComplete: () -> Unit = {}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.aisier.network
|
||||
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.aisier.network.entity.ApiResponse
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* @author : wutao
|
||||
* time : 2021/10/18
|
||||
* desc :
|
||||
* version: 1.1
|
||||
</pre> *
|
||||
*/
|
||||
typealias StateLiveData<T> = LiveData<ApiResponse<T>>
|
||||
typealias StateMutableLiveData<T> = MutableLiveData<ApiResponse<T>>
|
||||
|
||||
@MainThread
|
||||
fun <T> StateMutableLiveData<T>.observeState(
|
||||
owner: LifecycleOwner,
|
||||
listenerBuilder: ResultBuilder<T>.() -> Unit,
|
||||
) {
|
||||
observe(owner) { apiResponse -> apiResponse.parseData(listenerBuilder) }
|
||||
}
|
||||
|
||||
@MainThread
|
||||
fun <T> LiveData<ApiResponse<T>>.observeState(
|
||||
owner: LifecycleOwner,
|
||||
listenerBuilder: ResultBuilder<T>.() -> Unit,
|
||||
) {
|
||||
observe(owner) { apiResponse -> apiResponse.parseData(listenerBuilder) }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.aisier.network
|
||||
|
||||
import com.jeremyliao.liveeventbus.LiveEventBus
|
||||
|
||||
const val SHOW_TOAST = "show_toast"
|
||||
|
||||
/**
|
||||
* 为了不引入AppContext,临时方案,不推荐这么用
|
||||
*/
|
||||
@Deprecated("临时方案,不推荐这么用")
|
||||
fun toast(msg: String) {
|
||||
LiveEventBus.get<String>(SHOW_TOAST).post(msg)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.aisier.network.base
|
||||
|
||||
import com.aisier.network.BuildConfig
|
||||
import com.aisier.network.entity.*
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
open class BaseRepository {
|
||||
|
||||
suspend fun <T> executeHttp(block: suspend () -> ApiResponse<T>): ApiResponse<T> {
|
||||
//for test
|
||||
delay(500)
|
||||
runCatching {
|
||||
block.invoke()
|
||||
}.onSuccess { data: ApiResponse<T> ->
|
||||
return handleHttpOk(data)
|
||||
}.onFailure { e ->
|
||||
return handleHttpError(e)
|
||||
}
|
||||
return ApiEmptyResponse()
|
||||
}
|
||||
|
||||
/**
|
||||
* 非后台返回错误,捕获到的异常
|
||||
*/
|
||||
private fun <T> handleHttpError(e: Throwable): ApiErrorResponse<T> {
|
||||
if (BuildConfig.DEBUG) e.printStackTrace()
|
||||
// handlingExceptions(e)
|
||||
return ApiErrorResponse(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回200,但是还要判断isSuccess
|
||||
*/
|
||||
private fun <T> handleHttpOk(data: ApiResponse<T>): ApiResponse<T> {
|
||||
return if (data.isSuccess) {
|
||||
getHttpSuccessResponse(data)
|
||||
} else {
|
||||
// handlingApiExceptions(data.errorCode, data.errorMsg)
|
||||
ApiFailedResponse(data.errorCode, data.errorMsg)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功和数据为空的处理
|
||||
*/
|
||||
private fun <T> getHttpSuccessResponse(response: ApiResponse<T>): ApiResponse<T> {
|
||||
val data = response.data
|
||||
return if (data == null || data is List<*> && (data as List<*>).isEmpty()) {
|
||||
ApiEmptyResponse()
|
||||
} else {
|
||||
ApiSuccessResponse(data)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.aisier.network.base
|
||||
|
||||
import com.aisier.network.BuildConfig
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
abstract class BaseRetrofitClient {
|
||||
|
||||
companion object CLIENT {
|
||||
private const val TIME_OUT = 5
|
||||
}
|
||||
|
||||
private val client: OkHttpClient by lazy {
|
||||
val builder = OkHttpClient.Builder()
|
||||
.addInterceptor(getHttpLoggingInterceptor())
|
||||
.connectTimeout(TIME_OUT.toLong(), TimeUnit.SECONDS)
|
||||
handleBuilder(builder)
|
||||
builder.build()
|
||||
}
|
||||
|
||||
private fun getHttpLoggingInterceptor(): HttpLoggingInterceptor {
|
||||
val logging = HttpLoggingInterceptor()
|
||||
if (BuildConfig.DEBUG) {
|
||||
logging.level = HttpLoggingInterceptor.Level.BODY
|
||||
} else {
|
||||
logging.level = HttpLoggingInterceptor.Level.BASIC
|
||||
}
|
||||
return logging
|
||||
}
|
||||
|
||||
abstract fun handleBuilder(builder: OkHttpClient.Builder)
|
||||
|
||||
open fun <Service> getService(serviceClass: Class<Service>, baseUrl: String): Service {
|
||||
return Retrofit.Builder()
|
||||
.client(client)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.baseUrl(baseUrl)
|
||||
.build()
|
||||
.create(serviceClass)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.aisier.network.entity
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
open class ApiResponse<T>(
|
||||
open val data: T? = null,
|
||||
open val errorCode: Int? = null,
|
||||
open val errorMsg: String? = null,
|
||||
open val error: Throwable? = null,
|
||||
) : Serializable {
|
||||
val isSuccess: Boolean
|
||||
get() = errorCode == 0
|
||||
|
||||
override fun toString(): String {
|
||||
return "ApiResponse(data=$data, errorCode=$errorCode, errorMsg=$errorMsg, error=$error)"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
data class ApiSuccessResponse<T>(val response: T) : ApiResponse<T>(data = response)
|
||||
|
||||
class ApiEmptyResponse<T> : ApiResponse<T>()
|
||||
|
||||
data class ApiFailedResponse<T>(override val errorCode: Int?, override val errorMsg: String?) : ApiResponse<T>(errorCode = errorCode, errorMsg = errorMsg)
|
||||
|
||||
data class ApiErrorResponse<T>(val throwable: Throwable) : ApiResponse<T>(error = throwable)
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.aisier.network.entity
|
||||
|
||||
import com.aisier.network.toast
|
||||
import com.google.gson.JsonParseException
|
||||
import retrofit2.HttpException
|
||||
import java.net.SocketTimeoutException
|
||||
import java.util.concurrent.CancellationException
|
||||
|
||||
enum class HttpError(var code: Int, var errorMsg: String) {
|
||||
TOKEN_EXPIRE(3001, "token is expired"),
|
||||
PARAMS_ERROR(4003, "params is error")
|
||||
// ...... more
|
||||
}
|
||||
|
||||
internal fun handlingApiExceptions(code: Int?, errorMsg: String?) = when (code) {
|
||||
HttpError.TOKEN_EXPIRE.code -> toast(HttpError.TOKEN_EXPIRE.errorMsg)
|
||||
HttpError.PARAMS_ERROR.code -> toast(HttpError.PARAMS_ERROR.errorMsg)
|
||||
else -> errorMsg?.let { toast(it) }
|
||||
}
|
||||
|
||||
internal fun handlingExceptions(e: Throwable) = when (e) {
|
||||
is HttpException -> toast(e.message())
|
||||
|
||||
is CancellationException -> {
|
||||
}
|
||||
is SocketTimeoutException -> {
|
||||
}
|
||||
is JsonParseException -> {
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user