@@ -0,0 +1,71 @@
|
||||
package com.zhidao.roadcondition.net
|
||||
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import com.zhidao.roadcondition.exception.ApiException
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
import java.util.concurrent.TimeoutException
|
||||
|
||||
/**
|
||||
* 后续考虑加入Lifecycle管理,暂时不做扩展
|
||||
*/
|
||||
class CoroutineChain {
|
||||
|
||||
internal class CoroutineLifecycleListener(private val deferred: Deferred<*>, private val lifecycle: Lifecycle) :
|
||||
LifecycleObserver {
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
|
||||
fun cancelCoroutine() {
|
||||
if (deferred.isActive) {
|
||||
deferred.cancel()
|
||||
}
|
||||
lifecycle.removeObserver(this)
|
||||
}
|
||||
}
|
||||
|
||||
infix fun LifecycleOwner.start(start: (() -> Unit)): LifecycleOwner {
|
||||
start()
|
||||
return this
|
||||
}
|
||||
|
||||
infix fun <T> LifecycleOwner.request(loader: suspend () -> T): Deferred<T> {
|
||||
return request(loader, true)
|
||||
}
|
||||
|
||||
private fun <T> LifecycleOwner.request(loader: suspend () -> T, needAutoCancel: Boolean = true): Deferred<T> {
|
||||
val deferred = GlobalScope.async(Dispatchers.IO, start = CoroutineStart.LAZY) {
|
||||
loader()
|
||||
}
|
||||
if (needAutoCancel) {
|
||||
lifecycle.addObserver(CoroutineLifecycleListener(deferred, lifecycle))
|
||||
}
|
||||
return deferred
|
||||
}
|
||||
|
||||
fun <T> Deferred<T>.then(
|
||||
onSuccess: suspend (T) -> Unit,
|
||||
onError: suspend (java.lang.Exception) -> Unit,
|
||||
onComplete: (() -> Unit)? = null
|
||||
): Job {
|
||||
return GlobalScope.launch(context = Main) {
|
||||
try {
|
||||
val result = this@then.await()
|
||||
onSuccess(result)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
when (e) {
|
||||
is UnknownHostException -> onError.invoke(ApiException.NETWORK_API_EXCEPTION)
|
||||
is TimeoutException -> onError.invoke(ApiException.NETWORK_API_EXCEPTION)
|
||||
is SocketTimeoutException -> onError.invoke(ApiException.NETWORK_API_EXCEPTION)
|
||||
else -> onError(e)
|
||||
}
|
||||
} finally {
|
||||
onComplete?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.zhidao.roadcondition.net
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.zhidao.roadcondition.exception.ApiException
|
||||
import com.zhidao.roadcondition.exception.ApiException.Companion.NETWORK_API_EXCEPTION
|
||||
import com.zhidao.roadcondition.exception.ApiException.Companion.NULL_REQUEST_DATA_API_EXCEPTION
|
||||
import com.zhidao.roadcondition.model.BaseResponse
|
||||
import kotlinx.coroutines.*
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
import java.util.concurrent.TimeoutException
|
||||
|
||||
class Request<T> {
|
||||
private lateinit var loader: suspend () -> T
|
||||
|
||||
private var start: (() -> Unit)? = null
|
||||
|
||||
private var onSuccess: ((T) -> Unit)? = null
|
||||
|
||||
private var onError: ((java.lang.Exception) -> Unit)? = null
|
||||
|
||||
private var onComplete: (() -> Unit)? = null
|
||||
|
||||
private var addLifecycle: LifecycleOwner? = null
|
||||
|
||||
|
||||
infix fun loader(loader: suspend () -> T) {
|
||||
this.loader = loader
|
||||
}
|
||||
|
||||
infix fun start(start: (() -> Unit)?) {
|
||||
this.start = start
|
||||
}
|
||||
|
||||
infix fun onSuccess(onSuccess: ((T) -> Unit)?) {
|
||||
this.onSuccess = onSuccess
|
||||
}
|
||||
|
||||
infix fun onError(onError: ((java.lang.Exception) -> Unit)?) {
|
||||
this.onError = onError
|
||||
}
|
||||
|
||||
infix fun onComplete(onComplete: (() -> Unit)?) {
|
||||
this.onComplete = onComplete
|
||||
}
|
||||
|
||||
infix fun addLifecycle(addLifecycle: LifecycleOwner?) {
|
||||
this.addLifecycle = addLifecycle
|
||||
}
|
||||
|
||||
fun request() {
|
||||
request(addLifecycle)
|
||||
}
|
||||
|
||||
fun request(addLifecycle: LifecycleOwner?) {
|
||||
|
||||
GlobalScope.launch(context = Dispatchers.Main) {
|
||||
|
||||
start?.invoke()
|
||||
try {
|
||||
val deferred = GlobalScope.async(Dispatchers.IO, start = CoroutineStart.LAZY) {
|
||||
loader()
|
||||
}
|
||||
addLifecycle?.apply {
|
||||
lifecycle.addObserver(
|
||||
CoroutineChain.CoroutineLifecycleListener(
|
||||
deferred,
|
||||
lifecycle
|
||||
)
|
||||
)
|
||||
}
|
||||
val result = deferred.await()
|
||||
if (result != null && result is BaseResponse<*>) {
|
||||
if (result.code == 0) {
|
||||
onSuccess?.invoke(result)
|
||||
} else {
|
||||
throw ApiException(result.code, result.msg)
|
||||
}
|
||||
} else {
|
||||
throw NULL_REQUEST_DATA_API_EXCEPTION
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
//数据打点
|
||||
when (e) {
|
||||
is UnknownHostException -> onError?.invoke(NETWORK_API_EXCEPTION)
|
||||
is TimeoutException -> onError?.invoke(NETWORK_API_EXCEPTION)
|
||||
is SocketTimeoutException -> onError?.invoke(NETWORK_API_EXCEPTION)
|
||||
else -> onError?.invoke(java.lang.Exception(e.message))
|
||||
}
|
||||
} finally {
|
||||
onComplete?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T> request(buildRequest: Request<T>.() -> Unit) {
|
||||
Request<T>().apply(buildRequest).request()
|
||||
}
|
||||
|
||||
inline fun <T> LifecycleOwner.request(buildRequest: Request<T>.() -> Unit) {
|
||||
Request<T>().apply(buildRequest).request(this)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.zhidao.roadcondition.net
|
||||
|
||||
import com.zhidao.roadcondition.model.BaseResponse
|
||||
import com.zhidao.roadcondition.model.Results
|
||||
import com.zhidao.roadcondition.model.UploadResult
|
||||
import retrofit2.http.*
|
||||
|
||||
/**
|
||||
* 接口声明
|
||||
*/
|
||||
interface HttpApi {
|
||||
//获取城市策略
|
||||
@FormUrlEncoded
|
||||
@POST("yycp-geo-fence-carService/car/carStrategy/no/getCityStrategy/v1")
|
||||
suspend fun getCityStrategy(@FieldMap cityStrategy: Map<String, String>): BaseResponse<Results>
|
||||
|
||||
//上报情报数据
|
||||
@FormUrlEncoded
|
||||
@POST("/deva/car/path/no/addInfomation/v2")
|
||||
suspend fun uploadInformation(@FieldMap information: Map<String, String>): BaseResponse<UploadResult>
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.zhidao.roadcondition.net
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.utils.network.NetConfig
|
||||
import com.zhidao.roadcondition.constant.HttpConstants
|
||||
import okhttp3.Cache
|
||||
import okhttp3.Dns
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
class HttpClient private constructor(baseUrl: String) {
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_CONNECT_TIME = 30L
|
||||
const val DEFAULT_WRITE_TIMEOUT = 30L
|
||||
const val DEFAULT_READ_TIMEOUT = 30L
|
||||
|
||||
private var baseUrlClientMap = HashMap<String, HttpClient>()
|
||||
|
||||
fun getInstance(): HttpClient {
|
||||
val baseUrl = HttpConstants.getBaseUrl()
|
||||
var httpClient = baseUrlClientMap[baseUrl]
|
||||
if (httpClient == null) {
|
||||
synchronized(HttpClient::class.java) {
|
||||
if (httpClient == null) {
|
||||
httpClient = HttpClient(baseUrl)
|
||||
baseUrlClientMap[baseUrl] = httpClient!!
|
||||
}
|
||||
}
|
||||
}
|
||||
return httpClient!!
|
||||
}
|
||||
|
||||
fun getInstance(baseUrl: String): HttpClient {
|
||||
var httpClient = baseUrlClientMap[baseUrl]
|
||||
if (httpClient == null) {
|
||||
synchronized(HttpClient::class.java) {
|
||||
if (httpClient == null) {
|
||||
httpClient = HttpClient(baseUrl)
|
||||
baseUrlClientMap[baseUrl] = httpClient!!
|
||||
}
|
||||
}
|
||||
}
|
||||
return httpClient!!
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private var retrofit: Retrofit
|
||||
private var httpApi: HttpApi
|
||||
|
||||
init {
|
||||
retrofit = Retrofit.Builder()
|
||||
.client(getOkHttpClient())
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.baseUrl(baseUrl)
|
||||
.build()
|
||||
httpApi = retrofit.create(HttpApi::class.java)
|
||||
}
|
||||
|
||||
fun getHttpApi(): HttpApi {
|
||||
return httpApi
|
||||
}
|
||||
|
||||
private fun getOkHttpClient(): OkHttpClient {
|
||||
val builder = OkHttpClient.Builder()
|
||||
val httpLoggingInterceptor = HttpLoggingInterceptor()
|
||||
httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
|
||||
val cacheFile = File(AbsMogoApplication.getApp().applicationContext.cacheDir, "cache")
|
||||
val cache = Cache(cacheFile, 1024 * 1024 * 50)
|
||||
|
||||
val httpDns = NetConfig.instance().httpDns
|
||||
if (httpDns != null) {
|
||||
builder.dns(Dns { hostname: String? ->
|
||||
val addresses = httpDns.lookup(hostname)
|
||||
if (addresses != null && !addresses.isEmpty()) {
|
||||
return@Dns addresses
|
||||
}
|
||||
Dns.SYSTEM.lookup(hostname)
|
||||
})
|
||||
}
|
||||
|
||||
return builder
|
||||
.addInterceptor(httpLoggingInterceptor)
|
||||
.cache(cache)
|
||||
.connectTimeout(DEFAULT_CONNECT_TIME, TimeUnit.SECONDS)
|
||||
.readTimeout(DEFAULT_READ_TIMEOUT, TimeUnit.SECONDS)
|
||||
.writeTimeout(DEFAULT_WRITE_TIMEOUT, TimeUnit.SECONDS)
|
||||
.retryOnConnectionFailure(true)
|
||||
.build()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user