选Retrofit还是Ktor?手把手教你做决定

开发 项目管理
每次新建Android项目,选网络库就像在奶茶店点单——Retrofit是经典珍珠奶茶稳中求胜,Ktor是新出的芝士葡萄鲜果茶让人跃跃欲试。

每次新建Android项目,选网络库就像在奶茶店点单——Retrofit是经典珍珠奶茶稳中求胜,Ktor是新出的芝士葡萄鲜果茶让人跃跃欲试。

  • 当你急着对接API时,哪个能三分钟搞定?
  • 当产品经理突发奇想要加WebSocket时,哪个能优雅接招?
  • 当老板说要搞跨平台开发时,哪个能让你少掉头发?

举个栗子

Retrofit基础用法

// 1. 定义接口(就像点菜单)
interface NewsApiService {
    @GET("news/latest")
    suspendfun getLatestNews(): Response<List<News>>
}

// 2. 创建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() // 直接拿到新闻列表对象
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

适合场景:快速对接标准REST API

Ktor简单配置

// 1. 创建客户端(搭积木式配置)
val httpClient = HttpClient(CIO) {
    install(ContentNegotiation) {
        json(Json {
            ignoreUnknownKeys = true// JSON多了字段也不报错
        })
    }
    install(Logging) {
        logger = Logger.DEFAULT
        level = LogLevel.HEADERS // 想看请求头就调这个
    }
}

// 2. 发起请求(像发微信一样简单)
suspendfun fetchNews(): List<News> {
    return httpClient.get("https://api.rairmmd.com/news/latest").body()
}

// 3. 高级玩法:动态URL参数
val searchResults = httpClient.get {
    url("https://api.rairmmd.com/search")
    parameter("q", "热门") // 自动拼接到URL
    parameter("page", 2)
}.body<List<Article>>()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

亮点功能:想加什么功能就像装插件,比如给请求自动加Token:

HttpClient {
    install(Auth) {
        bearer {
            loadTokens { 
                BearerTokens("token", "1122334455667788") 
            }
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

实例对比

案例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) {
        // 处理异常
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

案例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
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

选择困难症急救包

当你需要...

  • 快速上线 → Retrofit(老司机踩油门)
// 三行代码搞定基础配置
Retrofit.Builder()
    .baseUrl("https://api.rairmmd.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 魔改请求 → Ktor(乐高式组装)
// 自定义超时时间+重试机制
HttpClient(CIO) {
    install(HttpTimeout) {
        requestTimeoutMillis = 15000
    }
    install(HttpRequestRetry) {
        maxRetries = 3
        retryOnExceptionIf { _, cause -> 
            cause is ConnectTimeoutException 
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 跨平台开发 → Ktor(一份代码走天下)
// 共享common模块中的网络请求代码
expect fun createHttpClient(): HttpClient

// iOS版实现
actual fun createHttpClient() = HttpClient(CIO) { /* iOS配置 */ }

// Android版实现
actual fun createHttpClient() = HttpClient(Android) { /* Android配置 */ }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

过来人的忠告

Retrofit踩坑记录

// 坑1:忘记加转换器会直接崩溃!
Retrofit.Builder()
    .baseUrl("https://api.rairmmd.com/")
    // 漏了.addConverterFactory()
    .build()

// 坑2:路径参数要用@Path标注
@GET("user/{id}/profile") // ✅ 正确姿势
suspend fun getUserProfile(@Path("id") userId: String)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

Ktor避雷指南

// 雷区1:协程作用域没管理好
// 错误示范 ❌
fun loadData() {
    GlobalScope.launch { 
        httpClient.get(...) // 可能导致内存泄漏
    }
}

// 正确姿势 ✅
viewModelScope.launch {
    httpClient.get(...)
}

// 雷区2:响应解析类型不匹配
val news = httpClient.get("...").body<News>() // News类字段要和JSON完全对应
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

终极选择器

需求

Retrofit

Ktor

要对接10个API且今晚就要上线

👍 稳如老狗

👎 现学来不及

要做直播间的弹幕推送

👎 轮询费劲

👍 长连接神器

老板说要"技术前沿"

👴 经典款

🚀 新潮之选

团队全是Java老手

👨💻 无缝衔接

🤯 语法震惊

想做小程序+APP+网页三端通吃

❌ 各玩各的

🌍 跨平台大法

小项目随便选,大项目看团队。实在纠结?

责任编辑:武晓燕 来源: 沐雨花飞碟
相关推荐

2017-05-18 12:45:35

数据分析数据理解数据

2015-07-29 16:33:12

IOS半透明引导

2020-07-23 14:39:28

系统权限设计

2021-04-06 22:48:41

数据集工具Python

2021-07-14 09:00:00

JavaFX开发应用

2011-01-10 14:41:26

2011-05-03 15:59:00

黑盒打印机

2011-03-28 16:14:38

jQuery

2023-04-26 12:46:43

DockerSpringKubernetes

2022-07-27 08:16:22

搜索引擎Lucene

2022-03-14 14:47:21

HarmonyOS操作系统鸿蒙

2022-01-08 20:04:20

拦截系统调用

2022-12-07 08:42:35

2011-02-22 13:46:27

微软SQL.NET

2021-12-28 08:38:26

Linux 中断唤醒系统Linux 系统

2021-02-26 11:54:38

MyBatis 插件接口

2021-10-03 20:26:56

系统模块标签

2020-10-13 11:21:57

框架自动化开发

2023-04-13 15:10:58

AI模型

2017-07-07 11:01:04

Spark性能调优
点赞
收藏

51CTO技术栈公众号