0.首先导入相关的库
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.8.0' // 导入第一行之后如果未成功导入okhttp库,手动导入,retrofit 是基于okhttp库进行封装的。
1.定义一个 Service 接口
interface PlaceService {//发起请求
@GET("v2/place") // 调用此方法时会发起一条GET请求
suspend fun getData(@Query("query") query: String, //自动开启子线程
@Query("token") token: String,
@Query("lang") lang: String
):DailyResponse
}
2.定义一个 ServiceCreator 单例类,用于生成 动态代理对象
object ServiceCreator {
val retrofit = Retrofit.Builder()
.baseUrl("https://api.caiyunapp.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
//创建动态代理对象,inline 内联函数使泛型不会擦除,reified关键字表明泛型要进行实化
inline fun <reified T> create() = retrofit.create(T::class.java)
}
3.定义一个 Network 单例类,用于提供网络请求的接口
object WeatherNetwork {
private val placeService = ServiceCreator.create<PlaceService>()
//内部开启一个新的IO线程
suspend fun getPlace(name: String) = placeService.getData(name,WeatherApplication.token, "zh_CN")
}
4.定义一个data class 用于接收数据
data class DailyResponse(val status: String, val result: Result) {//data类对数据做了一个很好的封装
data class Result(val daily: Daily)
data class Daily(val astro: List<Astro>, val temperature: List<Temperature>, val skycon: List<Skycon>)
data class Astro(val sunrise: Sunrise, val sunset: Sunset)
data class Sunrise(val time: String)
data class Sunset(val time: String)
data class Temperature(val max: Float, val min: Float)
data class Skycon(val date: Date, val value: String)
}
基于官方推荐的架构
0.View 从ViewModel 中获得数据
ViewMdel 中定义两个 LiveData ,第一个 LiveData的值改变时触发 switchMap() 函数,生成第二个LiveData 对象。
class HotViewModel : ViewModel() {
private var pageLiveData = MutableLiveData<Int>()
fun queryArticle(page: Int) {
pageLiveData.value = page
}
// 当 pageLivedata 改变时触发 switchMap() 函数,返回一个liveData
val articleLiveData = Transformations.switchMap(pageLiveData) {
page ->
HotRepository.getArticle(page)
}
}
1.ViewModel 从 Repository 中获取数据
Repository 可以提供本地数据,或者网络数据。
object HotRepository {
fun getArticle(page: Int) = liveData{ // livedata() 函数拥有协程作用域,同时返回LiveData对象
val res = try {
val articleResponse = ArticleNetwork.getArticle(page)
if (articleResponse.errorCode == 0) {
Result.success(articleResponse) // Result 类可以对结果进行封装,返回更加直观的信息
} else {
Result.failure(RuntimeException("errorCode is ${articleResponse.errorCode}"))
}
} catch (e: Exception) {
Result.failure<ArticleResponse>(e)
}
emit(res)
}
}