如何在Android项目中使用Ktor?

3,781 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 17 天,点击查看活动详情

如何在Android项目中使用Ktor?

1_8EovMmiPFQukLZ24N4pOZg.webp

Ktor是一个开源框架, 用于使用强大的Kotlin编程语言在连接系统中构建异步服务器和客户端. 它在协程上运行, 由JetBrains制作.

Ktor可以与OkHttpRetrofit等网络库相比.

Ktor是一个异步的HTTP客户端, 可以在多个平台上运行. Ktor客户端是为多种平台设计的, 如Android, Native(iOS和桌面), JVM和JavaScript. Ktor是建立在Kotlin移动多平台(KMM)上. 这意味着你可以用Kotlin创建iOS和Android应用程序, 并为这两个平台共享很大一部分Kotlin代码. 这意味着, Kotlin移动多平台使用Kotlin作为基础代码. 有了这个, 如果你想在安卓和iOS上共享代码, 你必须使用Kotlin库. Ktor客户端是一个基于Kotlin的库, 从而使其更容易实现KMM原则.

我们为什么使用Ktor?

在安卓系统中, 已经有一个非常强大的Retrofit库, 为什么我们还需要Ktor? 所以答案是Retrofit库是依赖于平台的, 如果我们想用在多平台的应用上, 就像Android最近推出的那样, 那么我们如何能从Retrofit中实现, 所以现在ktor想到了这个解决方案.

Ktor在内部使用协程进行异步编程, 这使得我们的代码非常简洁和最小化, 就像协程的挂起函数一样. 此外, 在我们的应用程序中添加头文件, 序列化, 日志等, 就像使用Retrofit一样也很容易.

目标

本指南将帮助你了解更多关于Ktor的信息. 我们将使用kotlin设置Ktor客户端, 向JSON API发出HTTP请求, 并显示数据.

在Android项目中设置Ktor客户端

添加所需的库

让我们添加所有处理和显示数据需要的必要库. 我们需要以下库:

Ktor依赖

// HTTP引擎: 处理网络请求.
implementation 'io.ktor:ktor-client-android:1.5.0'
// 用于设置JSON序列化和逆序列化, 向多平台项目推荐.
implementation 'io.ktor:ktor-client-serialization:1.5.0'
// kotlinx.serialization, 用于实体序列化
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1'
// 用于打印HTTP请求
implementation 'io.ktor:ktor-client-logging-jvm:1.5.0'

你必须在app.gradle文件中添加下一行:

plugins { 
    id 'kotlinx-serialization'
 } 

还需要在project.gradle中进行修改

plugins {  
    id 'com.android.application' version '7.2.2' apply false  
    id 'com.android.library' version '7.2.2' apply false  
    id 'org.jetbrains.kotlin.android' version '1.7.10' apply false  
    // id 'kotlinx-serialization' version "0.4.1" apply true  
    // id 'kotlin-multiplatform' version '1.3.20'  
    id 'kotlinx-serialization' version '1.3.20'  
}  
configurations {  
    ktorDependecy  
}  
  
dependencies {  
    ktorDependecy 'org.jetbrains.kotlin:kotlin-serialization:1.7.10'  
}

如果你创建的应用程序是多平台的, 这里*kotlin-multiplatform*是必须的, 否则你可以使用 *kotlinx-serialization*, 还有classpath org.jetbrains.kotlin:kotlin-serialization, 这是序列化和反序列化所需要的.

现在让我们在setting.gradle中添加maven: **https://kotlin.bintray.com/kotlinx**(如果使用gradle 7.3.3或更高版本), 同时需要添加插件. 这里我们同时使用了 kotlin-multiplatformkotlinx-serialization.

pluginManagement {  
    repositories {  
        gradlePluginPortal()  
        google()  
        mavenCentral()  
        maven { url "https://kotlin.bintray.com/kotlinx" } 
    } 
    resolutionStrategy {  
        eachPlugin {  
            if (requested.id.id == "kotlin-multiplatform") {  
                useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:$ { requested.version } ")  
            }  
            if (requested.id.id == "kotlinx-serialization") {  
                useModule("org.jetbrains.kotlin:kotlin-serialization:${ requested.version } ")  
            }  
        }  
    }  
}

现在我们创建一个HttpClient类来处理所有类型的请求, 但在这里只使用Android客户端.

import android.util.Log
import io.ktor.client.*
import io.ktor.client.engine.android.*
import io.ktor.client.features.*
import io.ktor.client.features.json.*
import io.ktor.client.features.json.serializer.*
import io.ktor.client.features.logging.*
import io.ktor.client.features.observer.*
import io.ktor.client.request.*
import io.ktor.http.*

private const val TIME_OUT = 6000

private val httpClientAndroid= HttpClient(Android){

    install(JsonFeature){

        serializer= KotlinxSerializer(kotlinx.serialization.json.Json{
            prettyPrint= true
            isLenient= true
            ignoreUnknownKeys= true
        })

        engine {
            connectTimeout= TIME_OUT
            socketTimeout= TIME_OUT
        }
    }

    install(Logging) {
        logger = object : Logger {
            override fun log(message: String) {
                Log.v("Logger Ktor =>", message)
            }
        }
        level = LogLevel.ALL
    }

    install(ResponseObserver) {
        onResponse { response ->
            Log.d("HTTP status:", "${response.status.value}")
        }
    }

    install(DefaultRequest) {
        header(HttpHeaders.ContentType, ContentType.Application.Json)
    }
}

现在, 让我们创建一个模型类, 以使用任何api:

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class UserEntity(@SerialName("age") val age: Int, @SerialName("count") val count: Int, @SerialName("name") val name: String)

在创建模型之后, 让我们创建一个API类, 它将处理所有的请求:

import io.ktor.client.*
import io.ktor.client.request.*

class UserApi(val client: HttpClient) {

    val END_POINT_GET_USER_KTOR="https://api.agify.io/"
    val SUB_END_POINT_GET_USER_KTOR="?name="
    val END_POINT_POST_USER_KTOR=""

    suspend fun getAgeOfPersonByName( userName: String):UserEntity=
        client.get("$END_POINT_GET_USER_KTOR$SUB_END_POINT_GET_USER_KTOR$userName")

    suspend fun addUser(user: UserEntity) {
        client.post<UserEntity>(END_POINT_POST_USER_KTOR) {
 body = user
        }
 }
}

现在我们创建一个资源库类, 所有需要的方法都将在其中提及:

interface UserRepository {
    suspend fun getAgeOfPersonByName( name: String): Either<Failure, UserEntity>
}

现在创建一个存储库实现类, 它将处理所有的请求和响应:

class UserRepositoryImpl( private val networkHandler: NetworkHandler,
                          private val userApi: UserApi):UserRepository {
    override suspend fun getAgeOfPersonByName(name: String): Either<Failure, UserModel> {
        when (networkHandler.isConnected) {
            true -> {
                try {
                    Either.Right(userApi.getAgeOfPersonByName(name).toDomain())
                } catch (e: Exception) {
                    Either.Left(e.toCustomExceptions())
                }
            }
            else -> Either.Left(Failure.NetworkConnection)
    }
}

现在在我们的项目中, 我们可以使用这个类来调用api方法, 并将在我们的调用者类中得到成功或失败的响应.

关于更多的细节, 我们将在下一部分讨论.

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 17 天,点击查看活动详情