Bootstrap

retrofit2 + 协程封装(suspendCancellableCoroutine )

package com.base.common

import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit

object RetrofitClient {
    private const val BASE_URL = "https://api.apiopen.top/"
    private val httpInterceptor: HttpInterceptor = HttpInterceptor()
    private val okHttpClient = OkHttpClient.Builder()
        .callTimeout(30, TimeUnit.SECONDS).addInterceptor(httpInterceptor)
        .cache(
            CacheHelper.instance?.cache
        )
        .readTimeout(15, TimeUnit.SECONDS)
        .writeTimeout(15, TimeUnit.SECONDS)
        .retryOnConnectionFailure(true)
        .build()
    private val retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .client(okHttpClient)
        .build()

    fun <T> create(serviceClass: Class<T>): T = retrofit.create(serviceClass)
}
import retrofit2.http.*
import com.test.login.UserBean as UserBean

interface ApiStore {
    // https://blog.csdn.net/c__chao/article/details/78573737 测试接口来自地址
    @GET("getSingleJoke?")
    fun login(@Query ("sid") sid:String): Call<BaseBean<UserBean>>
}
class ApiService {
    companion object {
        private var TAG: String = "ApiService"
        private var apiService = RetrofitClient.create(ApiStore::class.java)
        suspend fun ktLogin(request: BaseRequestParams): BaseBean<UserBean> {
            // 为了测试方便,使用测试接口这里传递的参数并非真正的请求参数
            //NetDataUtils.createJson(request)
            return apiService.login("28654780").awaitCall()
        }

        suspend fun upFile(request: BaseRequestParams, requestListener: RequestListener): BaseBean<UserBean> {
            //NetDataUtils.createJson(request)
            var file = File(request.id.toString())
            val requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file)
            val fileRequestBody = FileRequestBody(requestBody, requestListener)
            return apiService.uploadFile(fileRequestBody).awaitCall()
        }

        private suspend fun <T> Call<BaseBean<T>>.awaitCall(): BaseBean<T> {
            return suspendCancellableCoroutine {
                enqueue(object : RetrofitCallBack<T>() {
                    override fun success(data: BaseBean<T>) {
                        it.resumeWith(runCatching {
                             data
                        })
                    }

                    override fun failed(data: BaseBean<T>) {
                        it.resumeWith(runCatching {
                            data
                        })
                    }
                })
                it.invokeOnCancellation {
                    try {
                        cancel()
                    } catch (ex: Throwable) {
                        Log.e(TAG, "ApiService continuation invokeOnCancellation cancel Throwable")
                    }
                }
            }
        }
    }
}

package com.base.common

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

abstract class RetrofitCallBack<T> : Callback<BaseBean<T>> {
    @Suppress("UNCHECKED_CAST")
    override fun onResponse(call: Call<BaseBean<T>>, response: Response<BaseBean<T>>) {
            if (response.isSuccessful) {
                val body = response.body()
                // 网络请求成功返回的code值
                if (body?.code == ServiceCode.SUCCESS) {
                    success(body)
                } else {
                    // 接口调用返回错误码
                    failed(
                        BaseBean(
                            body!!.code ?: ServiceCode.HTTP_ERROR_CODE,
                            body.message ?: "",
                            Any() as T
                        )
                    )
                }
            } else {
                // 网络请求失败
                failed(BaseBean(response.code(), response.message(), Any() as T))
            }
    }

    @Suppress("UNCHECKED_CAST")
    override fun onFailure(call: Call<BaseBean<T>>, t: Throwable) {
            val errorBean = BaseBean(ServiceCode.HTTP_ERROR_CODE, t.message, Any() as T)
            failed(errorBean)
    }

    abstract fun success(data: BaseBean<T>)
    abstract fun failed(data: BaseBean<T>)
}

```kotlin
package com.base.common

open class BaseBean<T>(
    var code: Int? = 0,
    var message: String? = null,
    var result: T
)
package com.test.login

import com.base.common.BaseBean
open class UserBean {
    var sid: String? = null
    var text: String? = null
}

view module 调用方式

class UserModel : BaseViewModel() {
    val userBean: MutableLiveData<BaseBean<UserBean>> by lazy {
        MutableLiveData<BaseBean<UserBean>>()
    }

    fun getData() {
        viewModelScope.launch(Dispatchers.IO) {
            var start = System.currentTimeMillis()
            val clz = LoginRequestParams::class.java
            val request = NetDataUtils.createRequest(clz)
            // 收到请求的回调可以选择判断处理,然后发送通知给Activity
            val userData = ApiService.ktLogin(request)
            userBean.postValue(userData)
        }
    }
}

```kotlin
package com.base.common

class ServiceCode {
    companion object {
         const val SUCCESS = 200
         const val HTTP_ERROR_CODE = Int.MAX_VALUE - 1
    }
}

可能用到的包

api "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
api "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
api (['com.squareup.okhttp3:logging-interceptor:3.9.0',
      'com.squareup.retrofit2:retrofit:2.7.2',
      'com.squareup.retrofit2:converter-gson:2.7.2')
api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3'
;