選Retrofit還是Ktor?手把手教你做決定
每次新建Android項目,選網(wǎng)絡庫就像在奶茶店點單——Retrofit是經(jīng)典珍珠奶茶穩(wěn)中求勝,Ktor是新出的芝士葡萄鮮果茶讓人躍躍欲試。
- 當你急著對接API時,哪個能三分鐘搞定?
- 當產(chǎn)品經(jīng)理突發(fā)奇想要加WebSocket時,哪個能優(yōu)雅接招?
- 當老板說要搞跨平臺開發(fā)時,哪個能讓你少掉頭發(fā)?
舉個栗子
Retrofit基礎用法
// 1. 定義接口(就像點菜單)
interface NewsApiService {
@GET("news/latest")
suspendfun getLatestNews(): Response<List<News>>
}
// 2. 創(chuàng)建Retrofit實例(配菜過程)
val retrofit = Retrofit.Builder()
.baseUrl("https://api.rairmmd.com/")
.addConverterFactory(GsonConverterFactory.create()) // 自動把JSON變成對象
.client(OkHttpClient.Builder().addInterceptor(HttpLoggingInterceptor()).build())
.build()
// 3. 開始點菜!
val service = retrofit.create(NewsApiService::class.java)
val newsList = service.getLatestNews().body() // 直接拿到新聞列表對象
適合場景:快速對接標準REST API
Ktor簡單配置
// 1. 創(chuàng)建客戶端(搭積木式配置)
val httpClient = HttpClient(CIO) {
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true// JSON多了字段也不報錯
})
}
install(Logging) {
logger = Logger.DEFAULT
level = LogLevel.HEADERS // 想看請求頭就調(diào)這個
}
}
// 2. 發(fā)起請求(像發(fā)微信一樣簡單)
suspendfun fetchNews(): List<News> {
return httpClient.get("https://api.rairmmd.com/news/latest").body()
}
// 3. 高級玩法:動態(tài)URL參數(shù)
val searchResults = httpClient.get {
url("https://api.rairmmd.com/search")
parameter("q", "熱門") // 自動拼接到URL
parameter("page", 2)
}.body<List<Article>>()
亮點功能:想加什么功能就像裝插件,比如給請求自動加Token:
HttpClient {
install(Auth) {
bearer {
loadTokens {
BearerTokens("token", "1122334455667788")
}
}
}
}
實例對比
案例1:新聞列表接口(Retrofit版)
// 接口定義
@GET("newsList")
suspendfun getNewsListByCategory(
@Query("category") category: String,
@Query("page") page: Int
): Response<NewsResponse>
// 使用方式
viewModelScope.launch {
try {
val response = newsService.getNewsListByCategory("熱門", 1)
if (response.isSuccessful) {
_newsList.value = response.body()?.data ?: emptyList()
}
} catch (e: Exception) {
// 處理異常
}
}
案例2:同一個功能(Ktor版)
suspend fun loadNewsList(category: String, page: Int) {
val result = httpClient.get {
url("https://api.rairmmd.com/newsList")
parameters {
append("category", category)
append("page", page.toString())
}
}
if (result.status == HttpStatusCode.OK) {
val newsData = result.body<NewsResponse>()
_newsList.value = newsData.data
}
}
選擇困難癥急救包
當你需要...
- 快速上線 → Retrofit(老司機踩油門)
// 三行代碼搞定基礎配置
Retrofit.Builder()
.baseUrl("https://api.rairmmd.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
- 魔改請求 → Ktor(樂高式組裝)
// 自定義超時時間+重試機制
HttpClient(CIO) {
install(HttpTimeout) {
requestTimeoutMillis = 15000
}
install(HttpRequestRetry) {
maxRetries = 3
retryOnExceptionIf { _, cause ->
cause is ConnectTimeoutException
}
}
}
- 跨平臺開發(fā) → Ktor(一份代碼走天下)
// 共享common模塊中的網(wǎng)絡請求代碼
expect fun createHttpClient(): HttpClient
// iOS版實現(xiàn)
actual fun createHttpClient() = HttpClient(CIO) { /* iOS配置 */ }
// Android版實現(xiàn)
actual fun createHttpClient() = HttpClient(Android) { /* Android配置 */ }
過來人的忠告
Retrofit踩坑記錄
// 坑1:忘記加轉(zhuǎn)換器會直接崩潰!
Retrofit.Builder()
.baseUrl("https://api.rairmmd.com/")
// 漏了.addConverterFactory()
.build()
// 坑2:路徑參數(shù)要用@Path標注
@GET("user/{id}/profile") // ? 正確姿勢
suspend fun getUserProfile(@Path("id") userId: String)
Ktor避雷指南
// 雷區(qū)1:協(xié)程作用域沒管理好
// 錯誤示范 ?
fun loadData() {
GlobalScope.launch {
httpClient.get(...) // 可能導致內(nèi)存泄漏
}
}
// 正確姿勢 ?
viewModelScope.launch {
httpClient.get(...)
}
// 雷區(qū)2:響應解析類型不匹配
val news = httpClient.get("...").body<News>() // News類字段要和JSON完全對應
終極選擇器
需求 | Retrofit | Ktor |
要對接10個API且今晚就要上線 | ?? 穩(wěn)如老狗 | ?? 現(xiàn)學來不及 |
要做直播間的彈幕推送 | ?? 輪詢費勁 | ?? 長連接神器 |
老板說要"技術前沿" | ?? 經(jīng)典款 | ?? 新潮之選 |
團隊全是Java老手 | ???? 無縫銜接 | ?? 語法震驚 |
想做小程序+APP+網(wǎng)頁三端通吃 | ? 各玩各的 | ?? 跨平臺大法 |
小項目隨便選,大項目看團隊。實在糾結(jié)?