Kotlin中使用Retrofit

Retrofit

A type-safe HTTP client for Android and Java

Rerofit是Andorid最流行的HTTP框架,可以帮助开发者用最简单的代码实现API的调用。

本文主要介绍Kotlin中Retrofit的基本使用方法, 以帮助初学者快速入门

retrofit完整的使用涉及下面几个步骤:

  1. gradle配置
  2. 实现interfact
  3. 定义Model
  4. 实现retrofit对象
  5. 使用retrofit发送请求

1. gradle

compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.8.1'

2. interface

使用inerface定义请求用的API:

https://randomuser.me/api

上述API用interface定义后如下:

interface IApiService {
    @GET("api")
    fun apiDemo(): Call<RandomUserDemo>
}

interface的定义由以下元素构成

2.1 Request Method

通过@GET、@PUT注解可以定义HTTP的Request Method,注解中可以添加参数指定请求的path

@GET("users/list") //参数中指定URL的Path
@GET("users/list?sort=desc") //Path最后附带Query词

Path

URL的Path可以通过方法参数动态配置,如下,@Path注解的参数会传入到{...}中。

@GET("group/{id}/users")
fun groupList(@Path("id") groupId : Int) : Call<List<User>>

Query

Path末尾附带?的Query词,也同样可以通过参数动态传入,使用@Query注解,如下

@GET("group/{id}/users")
fun groupList(@Path("id") groupId: Int, @Query("sort") sort: String): Call<List<User>>

最终会转成以下URL

https://randomuser.me/group/3/users?sort=desc

当没有需要动态配置的内容,也就是方法可以没有参数时,在Kotlin中可以用变量代替方法,将Request Method注解声明在变量的Cusotm Getter方法上,如下:

@get:GET("api")
val apiDemo: Call<RandomUserDemo>

2.2 Request Body

Request Body用来存放Post的数据,@Body注解将一个JavaBean自动转换成Key-Value的Json格式作为Post的Body数据

@POST("users/new")
fun createUser(@Body user: User): Call<User>;

Form Encode

请求参数希望以表单数据形式(Key-Value)发送时,使用@FormUrlEncoded注解方法,@Field注解参数

@FormUrlEncoded
@POST("user/edit")
fun updateUser(@Field("first_name") first: String, @Field("last_name") last: String): Call<User>

Maltipart

希望发送Maltipart数据时,使用@Multipart注解方法,@Part注解参数

@Multipart
@PUT("user/photo")
fun updateUser(@Part("photo") photo: RequestBody, @Part("description") description: RequestBody): Call<User>

需要注意的是@Body、@FormUrlEncoded、@Maltipart作用相似,都是用来指定数据的发送方式,所以三者不能同时使用

2.3 Header

使用@Header注解可以配置HTTP请求的Header

@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
fun widgetList(): Call<List<Widget>>;

Header中可以同时配置多个项目

@Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
fun getUser(@Path("username") username: String): Call<User>

也可以通过参数进行动态配置

@GET("user")
fun getUser(@Header("Authorization") authorization: String): Call<User>

3.Model Class

根据HTTP的request/reponse中的Json数据需要定义本地对应的JavaBean:

{
    "info": {
        "page": 1, 
        "results": 1, 
        "seed": "7aed050e936ddbda", 
        "version": "1.1"
    }, 
    "results": [
        {
            "cell": "0486-036-722", 
            "dob": "1979-04-08 06:14:29", 
            "email": "roger.holt@example.com", 
            "gender": "male", 
            "id": {
                "name": "TFN", 
                "value": "023064228"
            }, 
            "location": {
                "city": "port macquarie", 
                "postcode": 1650, 
                "state": "western australia", 
                "street": "3769 dogwood ave"
            }, 
            "login": {
                "md5": "e7f8bb220a82a28ad9375081f022ff2f", 
                "password": "aaaaaaa", 
                "salt": "Q6J1Te1h", 
                "sha1": "e2ec839f88e8fdaddbb2a83877d9afd8342bf26c", 
                "sha256": "a602c4c64dc6fc1b94d6c98eedbf4383d79cd8894e21cc9f37f9fca3000cea05", 
                "username": "greenduck262"
            }, 
            "name": {
                "first": "roger", 
                "last": "holt", 
                "title": "mr"
            }, 
            "nat": "AU", 
            "phone": "09-2659-5113", 
            "picture": {
                "large": "https://randomuser.me/api/portraits/men/78.jpg", 
                "medium": "https://randomuser.me/api/portraits/med/men/78.jpg", 
                "thumbnail": "https://randomuser.me/api/portraits/thumb/men/78.jpg"
            }, 
            "registered": "2004-12-21 07:19:21"
        }
    ]
}

针对上面的Json数据,使用data class定义Model类如下:

data class RandomUserDemo(var info: Info,
                          var results: List<Result>)

data class Info(var seed: String,
                var results: Int,
                var page: Int,
                var version: String)

data class Result(var gender: String,
                  var email: String,
                  var registered: String,
                  var dob: String,
                  var phone: String,
                  var cell: String)

3.1 Custom Key Name

在data class转换Json的时候,可以通过@SerializedName改变key的名字

data class Result(var gender: String,
                  var email: String,
                  var registered: Int,
                  var dob: Int,
                  var phone: Int,
                  var cell: Int,
                  @SerializedName("id") var idMap: IdMap)

data class IdMap(var name: String,
                 var value: String)

注意这并不是retrofit提供的注解,而是gson的功能。retrofit的实际使用中经常使用Gson来负责Json转换部分,所以两个库经常一起使用

3.2 Transient

Model中不需要参与请求的成员,可以添加@Transient注解,因为@Transient注解的内容不会参与json转换中的序列化过程。注意transient不是gson或retrofit提供的,是jvm自带的特性,在java和kotlin中的用法略有不同,kotlin中是注解,java中是关键字。

public class IdMap {
    public long transient id = 0;
}

data class IdMap(@Transient var id: Long,
                 var name: String,
                 var value: String)

4. Retorfit

4.1 HttpClient

可以通过HttpClient完成一些基本配置,在Retrofit对象的创建中使用

 val httpBuilder: OkHttpClient.Builder get() {
        // create http client
        val httpClient = OkHttpClient.Builder()
                .addInterceptor(Interceptor { chain ->
                    val original = chain.request()

                    //header
                    val request = original.newBuilder()
                            .header("Accept", "application/json")
                            .method(original.method(), original.body())
                            .build()

                    return@Interceptor chain.proceed(request)
                })
                .readTimeout(30, TimeUnit.SECONDS)

        // log interceptor
        val loggingInterceptor = HttpLoggingInterceptor()
        loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
        httpClient.addInterceptor(loggingInterceptor)

        return httpClient
    }

httpClient用来进行一些基本配置,例如配置header,添加日志等。

4.2 Retorfit

  // core for controller
    val service: IApiService = create(IApiService::class.java)

    lateinit var retrofit: Retrofit

    fun <S> create(serviceClass: Class<S>): S {
        val gson = GsonBuilder()
                .serializeNulls()
                .create()

        // create retrofit
        retrofit = Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .baseUrl("http://your_base_url/") // Put your base URL
                .client(httpBuilder.build())
                .build()

        return retrofit.create(serviceClass)
    }

创建retorfit对象时,设置baseUrl、设置数据转换方式(gson)、并可以设置一个httpClient进行基础配置(这并不是必须的)。最重要的是通过interface(IApiService),返回一个IApiService同类型的动态代理对象,通过这个对象业务层可以使用IApiService中定义的方法发送请求。

4.3 singleton

retrofit对象一般以单例存在供全局调用,无需反复创建。例如,在dagger中可以如下配置

@Singleton
@Provides
internal fun providesApiService(): IApiService {
     return ApiService().service
}

5. 使用

retrofit对象创建后,可以对其进行同步或异步调用

5.1 同步

try {
      val response = API.apiDemo().execute()
      if (response.isSuccessful()) {
          return response.body()
      } else {
          // failed
      }
} catch (e: IOException e) {
      e.printStackTrace()
}

5.2 异步

API.apiDemo().enqueue(object : Callback<RandomUserDemo>() {
        fun onResponse(call: Call<RandomUserDemo>?, response: Response<RandomUserDemo>) {
            val demo: RandomUserDemo? = response.body()
        }

        fun onFailure(call: Call<RandomUserDemo?>?, t: Throwable?) {
           
        }
})

最后

本文大量篇幅放在Retrofit的创建过程,作为入门文章不想引入过多额外知识点,在实际使用中Retrofit更多地是配合RxJava使用,返回一个Observable/Single类型结果而非Call类型,Retrofit也可以返回LiveData、Flow等其他类型的结果,根据需求灵活配置也正是Retrofit的优势之一。

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Kotlin 使用 Retrofit 进行文件上传,你可以按照以下步骤进行操作: 1. 首先,确保你已经在项目添加了 Retrofit 和相应的依赖库。可以在 `build.gradle` 文件添加以下依赖: ```kotlin implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0' ``` 2. 创建一个接口,定义文件上传的 API。例如,假设你要上传文件到 `/upload` 路径,可以创建一个名为 `FileUploadService` 的接口: ```kotlin import okhttp3.MultipartBody import okhttp3.RequestBody import retrofit2.Call import retrofit2.http.Multipart import retrofit2.http.POST import retrofit2.http.Part interface FileUploadService { @Multipart @POST("/upload") fun uploadFile(@Part file: MultipartBody.Part): Call<ResponseBody> } ``` 3. 创建 Retrofit 实例,并且使用该实例创建 `FileUploadService` 的实例: ```kotlin import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory val retrofit = Retrofit.Builder() .baseUrl("http://your-base-url.com") .client(createOkHttpClient()) .addConverterFactory(GsonConverterFactory.create()) .build() fun createOkHttpClient(): OkHttpClient { val logger = HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY } return OkHttpClient.Builder() .addInterceptor(logger) .build() } val fileUploadService = retrofit.create(FileUploadService::class.java) ``` 4. 现在,你可以使用 `fileUploadService` 实例来上传文件。首先,创建一个 `File` 对象,表示要上传的文件。然后,将文件转换为 `RequestBody` 对象,并使用 `MultipartBody.Part` 将其添加到请求: ```kotlin import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.MultipartBody import java.io.File val file = File("path/to/your/file") val requestFile = file.asRequestBody("image/*".toMediaTypeOrNull()) val body = MultipartBody.Part.createFormData("file", file.name, requestFile) val call = fileUploadService.uploadFile(body) call.enqueue(object : Callback<ResponseBody> { override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) { // 文件上传成功处理 } override fun onFailure(call: Call<ResponseBody>, t: Throwable) { // 文件上传失败处理 } }) ``` 这样就完成了 Kotlin 使用 Retrofit 进行文件上传的过程。记得替换实际的 base URL 和文件路径。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fundroid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值