其他
优雅实现网络请求:协程+Flow+Retrofit+OkHttp
The following article is from 陆业聪 Author 陆业聪
1.1 Flow的用法
创建Flow:使用flow函数创建一个Flow,然后在Flow中使用emit函数发射数据。
val numbersFlow = flow {
for (i in 1..3) {
emit(i)
}
}
收集Flow:使用collect函数收集Flow中的数据,并对数据进行处理。
GlobalScope.launch {
numbersFlow.collect { number ->
println(number)
}
}
转换Flow:使用map、filter等转换操作符对Flow中的数据进行转换。
val squaresFlow = numbersFlow.map { number ->
number * number
}
组合Flow:使用combine、zip等组合操作符将多个Flow组合在一起。
val anotherFlow = flow {
for (i in 4..6) {
emit(i)
}
}
val combinedFlow = numbersFlow.combine(anotherFlow) { a, b ->
a + b
}
异常处理:使用catch、onCompletion等操作符处理Flow中的异常。
val errorFlow = flow {
for (i in 1..3) {
if (i == 2) {
throw RuntimeException("Error on $i")
}
emit(i)
}
}.catch { e ->
println("Caught exception: $e")
}
1.2 Flow的原理
Flow接口:代表一个数据流,可以通过collect函数进行收集。 flow函数:用于创建一个Flow,可以在其中使用emit函数发射数据。 collect函数:用于收集Flow中的数据,并对数据进行处理。 转换操作符:如map、filter等,用于对Flow中的数据进行转换。 组合操作符:如combine、zip等,用于将多个Flow组合在一起。 异常处理操作符:如catch、onCompletion等,用于处理Flow中的异常。
1.3 示例代码
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.*
fun main() = runBlocking {
// 创建Flow
val numbersFlow = flow {
for (i in 1..5) {
delay(100) // 模拟异步操作
emit(i)
}
}
// 转换Flow
val squaresFlow = numbersFlow.map { number ->
number * number
}
// 收集Flow
squaresFlow.collect { square ->
println("Square: $square")
}
// 组合Flow
val anotherFlow = flow {
for (i in 6..10) {
delay(100)
emit(i)
}
}
val combinedFlow = numbersFlow.combine(anotherFlow) { a, b ->
a + b
}
combinedFlow.collect { sum ->
println("Sum: $sum")
}
// 异常处理
val errorFlow = flow {
for (i in 1..3) {
if (i == 2) {
throw RuntimeException("Error on $i")
}
emit(i)
}
}.catch { e ->
println("Caught exception: $e")
}
errorFlow.collect { number ->
println("Number: $number")
}
}
通过这个示例,我们可以看到Flow提供了一种简洁、优雅的方式来处理异步、时间相关的操作。我们可以使用Flow的各种操作符对数据流进行转换、组合和异常处理,从而更好地组织和管理我们的代码。
2.1 Retrofit的用法
创建Retrofit实例:使用Retrofit.Builder创建一个Retrofit实例,并配置HTTP客户端(如OkHttp)、基本URL和转换器等。
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(OkHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.build()
定义API接口:创建一个Kotlin接口,并使用注解描述API的请求方式、路径、参数等信息。
interface ApiService {
@GET("user/{id}")
suspend fun getUser(@Path("id") id: Int): User
}
创建API接口实例:使用Retrofit实例的create方法创建API接口的实例。
val apiService = retrofit.create(ApiService::class.java)
调用API接口:直接调用API接口的方法发起网络请求。
GlobalScope.launch {
val user = apiService.getUser(1)
println("User: $user")
}
2.2 Retrofit的原理
Retrofit类:用于创建和配置Retrofit实例,以及创建API接口的实例。 注解:如@GET、@POST、@Path等,用于描述API的请求方式、路径、参数等信息。 转换器:如GsonConverterFactory、MoshiConverterFactory等,用于将HTTP响应转换为Kotlin或Java对象,以及将对象转换为请求体。 HTTP客户端:如OkHttpClient,用于实际发起网络请求。Retrofit内部使用HTTP客户端来处理网络请求和响应。
使用Retrofit.Builder创建一个Retrofit实例,并配置HTTP客户端、基本URL和转换器等。 使用注解定义API接口,并描述API的请求方式、路径、参数等信息。 使用Retrofit实例的create方法创建API接口的实例。Retrofit会使用动态代理创建一个实现了API接口的对象。 调用API接口的方法发起网络请求。Retrofit会根据方法的注解信息构建HTTP请求,并使用HTTP客户端发起请求。然后,Retrofit会使用转换器将HTTP响应转换为Kotlin或Java对象,并返回给调用者。
2.3 示例代码
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Path
import kotlinx.coroutines.runBlocking
import okhttp3.OkHttpClient
data class User(val id: Int, val name: String)
interface ApiService {
@GET("user/{id}")
suspend fun getUser(@Path("id") id: Int): User
}
fun main() = runBlocking {
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(OkHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.build()
val apiService = retrofit.create(ApiService::class.java)
val user = apiService.getUser(1)
println("User: $user")
}
这个示例展示了如何使用Retrofit优雅地实现网络请求。
val okHttpClient = OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.build()
interface ApiService {
@GET("user/{id}")
suspend fun getUser(@Path("id") id: Int): User
}
fun getUser(id: Int): Flow<User> = flow {
val apiService = retrofit.create(ApiService::class.java)
val user = apiService.getUser(id)
emit(user)
}.catch { e ->
// 处理异常
}
viewModelScope.launch {
getUser(1).collect { user ->
// 处理数据
}
}
在这个代码中,我们使用viewModelScope.launch来启动一个协程,并在协程中收集Flow。我们可以在collect函数中处理数据。
最后推荐一下我做的网站,玩Android: wanandroid.com ,包含详尽的知识体系、好用的工具,还有本公众号文章合集,欢迎体验和收藏!
推荐阅读:
扫一扫 关注我的公众号
如果你想要跟大家分享你的文章,欢迎投稿~
┏(^0^)┛明天见!