目录
- Read First
- My workflow
- Use Postman to query endpoint
- Model response object
- Create method in interface
- Create method in Repository
代码
YouTube版本
简介
- 我已经开始了我的下一个应用程序,这是一个Twitch客户端应用。这个系列将是我创建此应用时所面临的所有笔记和问题。
阅读第一个
- 本教程已经假设您熟悉Retrofit,并且在应用程序中启动并运行了Raterofit。本教程旨在成为一个更抽象的指南,并使个人对我的工作流程有广泛的了解。不要过多地关注细节,这是该工作流程中最有用的一系列步骤
使用翻新时的工作流程
- 当我与Twitch API合作时,我一直在进行改造。如此之多,以至于当我需要调用API的新端点时,我已经开发了一些工作流程。工作流由4个步骤组成:
1)使用Postman查询端点
2)对响应对象进行建模
3)在Retrofit接口中创建方法
4)在存储库层中创建方法
1)使用Postman查询端点
- 文档只能告诉我们太多,有时可能会过时或不正确。这就是为什么在开始编码之前,我喜欢用Postman查询端点的原因。这有两个主要好处:
1)验证我们正在使用所有适当的标头和参数击中适当的端点。
2)为我们提供了一个适当的示例,说明了响应对象是什么。我们必须验证响应对象是否在JSON中也很重要。 JSON是Retrofit将用于转换为我们的Kotlin对象的适当格式
2)响应对象建模
- 因此,假设我们正在使用get-streams API端点。经过成功的响应,我们将获得一个看起来像这样的JSON对象:
"data": [
{
"id": "40457151671",
"user_id": "582765062",
"user_login": "premiertwo",
"user_name": "PremierTwo",
"game_id": "33214",
"game_name": "Fortnite",
"type": "live",
"title": "fork knife @rubberross @ironmouse @aicandii | Tokyo, Japan | !discord",
"viewer_count": 3506,
"started_at": "2023-07-17T08:14:13Z",
"language": "en",
"thumbnail_url": "https://static-cdn.jtvnw.net/previews-ttv/live_user_premiertwo-{width}x{height}.jpg",
"tag_ids": [],
"tags": [
"Improv",
"Forehead",
"AMA",
"VoiceActing",
"Japan",
"Travel",
"English",
"NoSpoilers"
],
"is_mature": false
},
]
- 我们建模的响应对象将看起来像这样:
data class FollowedLiveStreams(
val data:List<StreamData>
)
data class StreamData(
val id:String,
@SerializedName("user_id")
val userId:String,
@SerializedName("user_login")
val userLogin:String,
@SerializedName("user_name")
val userName:String,
@SerializedName("game_id")
val gameId:String,
@SerializedName("game_name")
val gameName:String,
val type:String,
val title:String,
@SerializedName("viewer_count")
val viewerCount:Int,
@SerializedName("started_at")
val startedAt:String,
val language:String,
@SerializedName("thumbnail_url")
val thumbNailUrl:String,
@SerializedName("tag_ids")
val tagIds:List<String>,
val tags:List<String>,
@SerializedName("is_mature")
val isMature:Boolean
)
- 尝试建模JSON响应对象时,您应该寻找两件事:
1)[]方括号:表示列表。这就是为什么KOTLIN数据类版本"tags": ["Improv"]
是val tags:List<String>
2){}卷曲括号:指示一个新对象。这就是为什么我们将JSON响应对象建模为两个类的原因。请注意,其"data": [ {
是如何的,紧随其后的方括号是卷曲括号告诉我们data
是对象的列表。这导致我们的data:List<StreamData>
值
3)在翻新接口中创建方法
- 现在是我们修改将表示HTTP调用的接口的部分。假设我们仍在使用get-streams API,则该呼叫看起来像这样:
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Query
@GET("streams/followed")
suspend fun getFollowedStreams(
@Header("Authorization") authorization:String,
@Header("Client-Id") clientId:String,
@Query("user_id") userId:String
): Response<FollowedLiveStreams>
- 请注意,我们如何使用
@Header
,@Query
来定义查询参数和标题的动态值。另外,看看返回对象是Response<FollowedLiveStreams>
,我们正在使用以前创建的FollowedLiveStreams
。改造将自动将JSON对象映射到我们的FollowedLiveStreams
对象
4)在存储库层中创建方法
- 现在,在存储库层的内部,我们可以将实际调用API进行,就像这样:
class TwitchRepoImpl(
private val twitchClient: TwitchClient = TwitchRetrofitInstance.api
) {
suspend fun getFollowedLiveStreams(
authorizationToken: String,
clientId: String,
userId: String
): Flow<Response<FollowedLiveStreams>> = flow{
emit(Response.Loading)
val response = twitchClient.getFollowedStreams(
authorization = authorizationToken,
clientId = clientId,
userId = userId
)
if (response.isSuccessful){
emit(response.body())
}else{
emit(Response.Failure(Exception("Error!, code {${response.code()}}")))
}
}
}
- 上面的代码似乎有些混乱,但要澄清事物,响应对象是我自己的创建:
sealed class Response<out T> {
object Loading: Response<Nothing>()
data class Success<out T>(
val data:T
):Response<T>()
data class Failure(
val e:Exception
):Response<Nothing>()
}
-
我正在从
getFollowedLiveStreams()
返回Kotlin Flows,因此我的下游类(viewModels)能够在这种方法上调用collect{}
,并根据响应是加载,成功或失败 而做出不同的反应。
-
我们定义了存储库层内部的方法后,我们可以随意使用该方法。
结论
- 感谢您抽出宝贵的时间阅读我的博客文章。如果您有任何疑问或疑虑,请在下面发表评论或在Twitter上与我联系。