ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

【Ktor挖坑日记】还在用Retrofit网络请求吗?试试Ktor吧

【Ktor挖坑日记】还在用Retrofit网络请求吗?试试Ktor吧 Ktor官方对Ktor的描述是Create asynchronous client and server applications. Anything from microservices to multiplatform HTTP client apps in a simple way. Open Source, free, and fun!创建异步客户端和和服务器应用从微服务到多平台HTTP客户端应用程序都可以用一种简单的方式完成。开源、免费、有趣它具有轻量级可扩展性强多平台异步的特性。轻量级和可扩展性是因为它的内核比较简单并且当需要一些功能的时候可以加入别的插件到项目中并不会造成功能冗余。并且Ktor的扩展是使用插拔的方式使用起来非常简单异步Ktor内部是使用Kotlin协程来实现异步这对于熟悉Kotlin的Android开发非常友好。看到这里可能一头雾水下面将用一个比较简单的例子来带大家入坑Ktor等看完这篇文章之后就会对Ktor的这些特性有进一步的了解。小例子 —— 看猫咪引入依赖在app模块的gradle中引入依赖plugins { ... id org.jetbrains.kotlin.plugin.serialization version 1.7.10 // 跟Kotlin版本一致 } dependencies { ... // Ktor def ktor_version 2.1.0 implementation io.ktor:ktor-client-core:$ktor_version implementation io.ktor:ktor-client-android:$ktor_version implementation io.ktor:ktor-client-content-negotiation:$ktor_version implementation io.ktor:ktor-serialization-kotlinx-json:$ktor_version }稍微解释一下这两个依赖Ktor的客户端内核由于本APP是部署在Android上的因此需要引入一个Android依赖Android平台和其他平台的不同点在于Android具有主线程的概念Android不允许在主线程发送网络请求而在Kotlin协程中就是主调度器的概念其内部是post任务到主线程Handler中这里就不展开太多。当然如果要使用OkHttp也是可以的implementation io.ktor:ktor-client-okhttp:$ktor_version如果想应用到其他客户端平台可以使用CIO第三个简单来说就是数据转换的插件例如将远端发送来的数据可以是CBOR、Json、Protobuf转换成一个个数据类。而第四个就是第三个的衍生插件相信用过kotlin-serialization的人会比较熟悉是Kotlin序列化插件本次引用的是json类似于Gson可以将json字符串转换成数据类。当然如果需要其他插件可以到官网上看看例如打印日志Loggingimplementation ch.qos.logback:logback-classic:$logback_version implementation io.ktor:ktor-client-logging:$ktor_version创建HttpClient首先创建一个HttpClient实例val httpClient HttpClient(Android) { defaultRequest { url { protocol URLProtocol.HTTP host 你的host port 你的端口 } } install(ContentNegotiation) { json() } }创建的时候是使用DSL语法的这里解释一下其中使用的两个配置defaultRequest给每个HTTP请求加上BaseUrl例如请求/get-cat就会向http://${你的host}:${你的端口}/get-cat发起HTTP请求。ContentNegotiation引入数据转换插件。json引入自动将json转换数据类的插件。定义数据类Serializable data class Cat( val name: String, val description: String, val imageUrl: String )此处给猫咪定义名字、描述和图片url需要注意的是需要加上Serializable注解这是使用kotlin-serialization的前提条件而需要正常使用kotlin-serialization需要在app模块的build.gradle加上以下pluginplugins { ... id org.jetbrains.kotlin.plugin.serialization version 1.7.10 // 跟Kotlin版本一致 }创建APIinterface CatSource { suspend fun getRandomCat(): ResultCat companion object { val instance CatSourceImpl(httpClient) } } class CatSourceImpl( private val client: HttpClient ) : CatSource { override suspend fun getRandomCat(): ResultCat runCatching { client.get(random-cat).body() } }此处声明一个CatSource接口接口中声明一个获取随机小猫咪的函数并且对该接口进行实现。suspendHttpClient的方法大多数为suspend函数例如例子中的get为suspend函数因此接口也要定义成suspend函数。ResultResult为Kotlin官方包装类具有success和failure两个方法可以包装成功和失败两种数据可以简单使用runCatching来返回ResultInlineOnly SinceKotlin(1.3) public inline fun T, R T.runCatching(block: T.() - R): ResultR { return try { Result.success(block()) } catch (e: Throwable) { Result.failure(e) } }body获取返回结果由于内部协程实现因此不用担心阻塞主线程的问题由于引入了ContentNegotiation因此获取到结果之后可以对其进行转换转换成实际数据类。展示ViewModelclass MainViewModel : ViewModel() { private val catSource CatSource.instance private val _catState MutableStateFlowUiStateCat(UiState.Loading) val catState _catState.asStateFlow() init { getRandomCat() } fun getRandomCat() { viewModelScope.launch { _catState.value UiState.Loading // fold 方法可以用来对 Result 的结果分情况处理 catSource.getRandomCat().fold( onSuccess { _catState.value UiState.Success(it) }, onFailure { _catState.value UiState.Failure(it) } ) } } } sealed class UiStateout T { object Loading: UiStateNothing() data class SuccessT(val value: T): UiStateT() data class Failure(val exc: Throwable): UiStateNothing() } inline fun T UiStateT.onState( onSuccess: (T) - Unit, onFailure: (Throwable) - Unit {}, onLoading: () - Unit {} ) { when(this) { is UiState.Failure - onFailure(this.exc) UiState.Loading - onLoading() is UiState.Success - onSuccess(this.value) } }Activity界面比较简单因此用Compose实现class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { KittyTheme { Column( modifier Modifier .fillMaxWidth() .padding(32.dp) ) { val viewModel: MainViewModel viewModel() val catState by viewModel.catState.collectAsState() catState.onState( onSuccess { cat - AsyncImage(model cat.imageUrl, contentDescription cat.name) Spacer(modifier Modifier.height(8.dp)) Text( text cat.name, fontWeight FontWeight.SemiBold, fontSize 20.sp ) Spacer(modifier Modifier.height(8.dp)) Text(text cat.description) }, onFailure { Text(text Loading Failure!) }, onLoading { CircularProgressIndicator() } ) Button( onClick viewModel::getRandomCat, modifier Modifier.align(Alignment.End) ) { Text(text Next Cat!) } Spacer(modifier Modifier.height(8.dp)) } } } } }对state分情况展示加载中就展示转圈圈。成功就展示猫咪图片、猫咪名字、猫咪描述。失败就展示加载失败。展示图片的AsyncImage来自于Coil展示库传入imageUrl就好啦使用Kotlin编写内部使用协程实现异步。我们运行一下吧总结一下是不是很简单捏看起来好像很多其实核心用法就三个实例HttpClient在HttpClient中配置插件调用get或者post方法由于内部使用了协程来进行异步因此不用担心主线程阻塞令我觉得比较香的是数据转换插件可以再也不用担心数据转换了。并且支持例如XML、CBOR、Json等等也不会担心后端会给我们发来什么数据格式了。还有一个文中没有用到的是Logging插件可以在logcat打印给服务端发了什么服务端给客户端发了什么调试API起来也很方便跟后端拉扯起来也很有底气另外Android插件不支持WebSocket但是Okhttp和CIO支持实际使用中可以用后者创建httpClient服务端创建项目服务端不是重点就简单提一下贴一下代码使用IntelliJ IDEA Ultimate可以直接创建Ktor工程要是用社区版就去ktor.io/create/创建。工程名字。2. 配置插件官方很多插件不用想着一下子就添加完需要用的时候再像客户端一样引入依赖就好。3. 创建项目下载打开。编写代码到Application.kt看一下主函数fun main() { embeddedServer(Netty, port 你的端口, host 0.0.0.0) { configureRouting() configureSerialization() }.start(wait true) }配置Routing插件fun Application.configureRouting() { routing { randomCat() static { resources(static) } } } fun Route.randomCat() { get(/random-cat) { // 随便回一直猫咪给客户端 call.respond(cats.random()) } } //本地IPV4地址 private const val BASE_URL http://${你的host}:${你的端口} private val cats listOf( Cat(夺宝1号, 这是一只可爱的小猫咪, $BASE_URL/cats/cat1.jpg), Cat(夺宝2号, 这是一只可爱的小猫咪, $BASE_URL/cats/cat2.jpg), Cat(夺宝3号, 这是一只可爱的小猫咪, $BASE_URL/cats/cat3.jpg), Cat(夺宝4号, 这是一只可爱的小猫咪, $BASE_URL/cats/cat4.jpg), Cat(夺宝5号, 这是一只可爱的小猫咪, $BASE_URL/cats/cat5.jpg), Cat(夺宝6号, 这是一只可爱的小猫咪, $BASE_URL/cats/cat6.jpg), Cat(夺宝7号, 这是一只可爱的小猫咪, $BASE_URL/cats/cat7.jpg), ) Serializable data class Cat( val name: String, val description: String, val imageUrl: String )配置Serialization插件fun Application.configureSerialization() { install(ContentNegotiation) { json() } }放入图片资源我放了七只猫咪图片。然后跑起来就好啦去手机上看看效果吧又总结一次客户端和服务端使用方式是比较相似的这也非常友好由于也是使用Kotlin作为后端那很多代码都可以拷贝了例如文中的数据类Cat甚至可以直接拷贝过来。Ktor用起来非常方便由于其Okhttp插件的存在在全Kotlin的Android项目中甚至可以考虑Ktor而不是Retrofit当然Retrofit也是非常优秀的网络请求库。关于Ktor的坑先开到这啦参考ktor.io/作者米奇律师链接https://juejin.cn/post/7136829279903416333更多Android学习资料可点击下方卡片~
返回列表