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'

Okhttp断开重连网络导致的问题:
1.java.net.UnknownHostException: Unable to resolve host “your.domain.com”: No address associated with hostname
2.timeout
处理方式:okhttpclient.connectionPool().evictAll();
https://blog.csdn.net/u011123714/article/details/112377214

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然,我很愿意回答您的问题。下面是一个 Kotlin + 协程 + Retrofit + MVVM 实现网络请求的示例: 1. 在 build.gradle 中添加以下依赖: ``` implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0' implementation 'com.squareup.retrofit2:retrofit:2.8.1' implementation 'com.squareup.retrofit2:converter-gson:2.8.1' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9' ``` 2. 创建 Retrofit 接口: ```kotlin interface ApiService { @GET("users/{user}/repos") suspend fun getRepos(@Path("user") user: String): List<Repo> } ``` 3. 创建数据模型: ```kotlin data class Repo(val name: String) ``` 4. 创建 Repository: ```kotlin class MainRepository(private val apiService: ApiService) { suspend fun getRepos(user: String): List<Repo> { return apiService.getRepos(user) } } ``` 5. 创建 ViewModel: ```kotlin class MainViewModel(private val repository: MainRepository) : ViewModel() { private val _repos = MutableLiveData<List<Repo>>() val repos: LiveData<List<Repo>> = _repos fun getRepos(user: String) { viewModelScope.launch { _repos.value = repository.getRepos(user) } } } ``` 6. 创建 Activity/Fragment: ```kotlin class MainActivity : AppCompatActivity() { private lateinit var viewModel: MainViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val apiService = Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(GsonConverterFactory.create()) .build() .create(ApiService::class.java) val repository = MainRepository(apiService) viewModel = ViewModelProvider(this, MainViewModelFactory(repository))[MainViewModel::class.java] viewModel.repos.observe(this, Observer { repos -> // do something with repos }) viewModel.getRepos("octocat") } } ``` 以上就是一个使用 Kotlin + 协程 + Retrofit + MVVM 实现网络请求的示例。希望对您有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值