[Android]网络框架之Retrofit(kotlin)

简介: [Android]网络框架之Retrofit(kotlin)

Retrofit简介


Retrofit是一款由Square公司开发的网络库,但是它和OkHttp的定位完全不同。

OkHttp侧重的是底层通信的实现,而Retrofit侧重的是上层接口的封装。

事实上,Retrofit就是Square公司在OkHttp的基础上进一步开发出来的应用层网络通信库,使得我们可以用更加面向对象的思维进行网络操作。

Retrofit的项目主页地址是:

https://github.com/square/retrofit

添加依赖

implementation 'com.squareup.retrofit2:retrofit:2.9.0'

添加网络权限

<uses-permission android:name="android.permission.INTERNET" />

Retrofit基本使用

1.根据Http接口创建kotlin接口

interface HttpbinService {
    @GET("get")
    fun get(@Query("userName")userName: String,@Query("password") pwd: String):Call<ResponseBody>
    @POST("post")
    @FormUrlEncoded
    fun post(@Field("userName")userName:String, @Field("password")pwd:String):Call<ResponseBody>
}

2.创建Retrofit对象,并生成接口实现类对象。

val retrofit = Retrofit.Builder().baseUrl("https://www.httpbin.org/").build()
 val httpbinService: HttpbinService = retrofit.create(HttpbinService::class.java)

3.接口实现类对象调用对应方法获得响应。

val call: retrofit2.Call<ResponseBody> = httpbinService.post("xxx", "xxx")
        call.enqueue(object : retrofit2.Callback<ResponseBody> {
            //请求完成
            override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
                try {
                    Log.e("data", "${response.body()?.string()}")
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
            //请求失败
            override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
                TODO("Not yet implemented")
            }
        })

Retrofit的注解


方法注解:@GET,@POST,@PUT,@DELECTE,@PATH,@HEAD,@OPTIONS,@HTTP

标记注解:@FormUrlEncoded,@Multiparty,@Streaming

参数注解:@Query,@QueryMap,@Body,@Field,@FieldMap,@Part,@PartMap

其他注解:@Path,@Header,@Headers,@Url

(1) @GET

https://www.httpbin.org/get

@GET("get")
    fun get():Call<ResponseBody>

这里使用了一个@GET注解,表示当调用get()方法时Retrofit会发起一条GET请求,请求的地址就是我们在@GET注解中传入的具体参数。另外,get()方法的返回值必须声明成Retrofit中内置的Call类型,并通过泛型来指定服务器响应的数据应该转换成什么对象。

(2) @GET, @Query

https://www.httpbin.org/get?userName=<userName>&password=<pwd>

@GET("get")
    fun get(@Query("userName")userName: String,@Query("password") pwd: String):Call<ResponseBody>

这里在get方法中添加了两个参数userName和pwd,并使用 @Query对他们进行声明,这样当发起网络请求时,Retrofit就会自动按照带参数GET请求的格式将这两个参数构建到请求地址中。

(3)@POST,@FormUrlEncoded,@Field

@POST("post")
    @FormUrlEncoded
    fun post(@Field("userName")userName:String, @Field("password")pwd:String):Call<ResponseBody>

这里使用了一个@POST注解,表示当调用post()方法时Retrofit会发起一条POST请求,请求的地址就是我们在@POST注解中传入的具体参数。POST请求如果参数,就需要添加 @FormUrlEncoded注解,表示请求实体是一个表单,每个键值对需要使用@Field注解。

@POST("post")
    @FormUrlEncoded
    fun post(@Field("userName")userName:String, @Field("password")pwd:String):Call<ResponseBody>

(4) @Path

@POST("{id}")
    @FormUrlEncoded
    fun postInPath(@Path("id")path:String,@Field("userName")userName:String, @Field("password")pwd:String):Call<ResponseBody>

在POST注解指定的接口地址当中,这里使用了{id}的占位符,然后又在postInPath方法中添加了一个path参数,并使用@Path{”id“}注解来声明这个参数。这样当调用postInPath方法发起请求时,Retrofit会自动将id参数的值替换到占位符的位置,从而组成一个合法的请求地址。

(5)@HTTP

@HTTP(method = "GET", path = "get", hasBody = true)
    fun http(@Query("username")userName: String,@Query("password") pwd: String):Call<ResponseBody>

@HTTP注解,通过method设置请求方式(注意大小写),path设置网络请求地址,hasBody是否有请求体。

(6)@Body

@POST("post")
    fun postBody(@Body body:RequestBody):Call<ResponseBody>

POST请求并给它加入@Body注解,@Body可以传递自定义类型数据给服务器。如果我们声明参数的类型时会怎样呢?

@POST("post")
    fun postBody(@Body body:Data):Call<ResponseBody>

我们在postBody方法中声明Data类型的参数,这样当Retrofit发送POST请求的时候,就会自动将Data对象中的数据转换成JSON格式的文本,并放到HTTP请求的body部分,服务器在收到请求之后只需要将这部分解析出来。

(@Body注解不能与@FormUrlEncoded和@Multiparty一起用)

(7)@Header,@Headers

@Headers("os:android","version:1.0")
    @POST("post")
    fun postWithHeaders( @Header("a") a:String):Call<ResponseBody>

静态添加header声明,使用 @Headers

动态添加header声明,使用 @Header

(8)@Url

@POST
    fun postUrl(@Url url:String):Call<ResponseBody>

@Url注解重写网络接口地址

Retrofit的转换器


在我们接到服务器的相应之后,目前无论是OkHttp还是Retrofit都只能接收到String字符串类型的数据,在实际开发中,我们经常需要对字符串进行解析将其转换为一个对象,比如服务器响应数据为JSON格式字符串,那么我们可以利用GSON库完成发序列化的操作。而Retrofit提供了多个转换器使得响应能够完成自动的数据转换,以JSON解析为例:

添加依赖

implementation 'com.squareup.retrofit2:converter-gson:2.6.1'

由于retrofit会借助GSON将JSON数据转换成对象,需要新建一个类

class App(val id:String,val name:String,val price:Double,val imagePath:String) {
}

新建一个接口,获取JSON数据

interface AppService {
    @GET("get_JsonArray.json")
    fun getAppData(): Call<List<App>>
}

由于这里服务器的接口是HTTP,从Android 9.0系统开始,应用程序默认允许使用HTTPS类型的网络请求,而我用的Apache服务器现在使用的是HTTP,所以要进行网络安全配置。

<application

   android:allowBackup="true"

   android:dataExtractionRules="@xml/data_extraction_rules"

   android:fullBackupContent="@xml/backup_rules"

   android:icon="@mipmap/ic_launcher"

   android:label="@string/app_name"

   android:roundIcon="@mipmap/ic_launcher_round"

   android:supportsRtl="true"

   android:theme="@style/Theme.OkhttpRetrofit"

   tools:targetApi="31"

   android:networkSecurityConfig="@xml/network_config">

新建network_config.xml文件

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>
</network-security-config>

最后,使用如下代码即可发起Retrofit请求:

val retrofit=Retrofit.Builder()
            .baseUrl("http://10.0.2.2/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        val appService:AppService=retrofit.create(AppService::class.java)
        appService.getAppData().enqueue( object:retrofit2.Callback<List<App>>{
            override fun onResponse(
                call: retrofit2.Call<List<App>>,
                response: retrofit2.Response<List<App>>
            ) {
               val list=response.body()
                if(list!=null){
                    for(a in list){
                        Log.e("data","id=${a.id} name=${a.name} price=${a.price} imagePath=${a.imagePath}")
                    }
                }
            }
            override fun onFailure(call: retrofit2.Call<List<App>>, t: Throwable) {
                t.printStackTrace()
            }
        })

文件的上传与下载


上传文件

fun uploadFileTest(){
        thread{
            try {
                val retrofit = Retrofit.Builder().baseUrl("https://www.httpbin.org/").build()
                val uploadService: UploadService = retrofit.create(UploadService::class.java)
                val file=File(externalCacheDir,"a.txt")
                if (!file.exists()){
                    file.createNewFile();
                }
                val part:MultipartBody.Part=MultipartBody.Part.createFormData("file",file.name,file.asRequestBody("text/plain".toMediaType()))
                val call=uploadService.upload(part)
                Log.e("uploadFileTest","${call.execute().body()?.string()}")
            }catch (e:Exception){
                e.printStackTrace()
            }
        }
    }

下载文件

//下载文件
    fun downloadTest(){
       thread {
           try {
               val retrofit = Retrofit.Builder().baseUrl("https://www.httpbin.org/").build()
               val uploadService: UploadService = retrofit.create(UploadService::class.java)
               val response=uploadService.downloaduri("https://dl2.xmind.cn/Xmind-for-Windows-x64bit-22.11.2677.exe").execute()
               val inputStream=response.body()?.byteStream()
               val file=openFileOutput("data111",Context.MODE_PRIVATE)
               val bis = BufferedInputStream(inputStream)
               val buffer = ByteArray(4096)
               var len: Int
               while (((bis.read(buffer)).also { len = it }) != -1) {
                   file.write(buffer, 0, len)
               }
               bis.close()
           }catch (e:Exception){
               e.printStackTrace()
           }
       }
    }
目录
相关文章
|
5天前
|
设计模式 Android开发 Kotlin
Android经典实战之Kotlin委托模式和by关键字
本文介绍了Kotlin中`by`关键字在类及属性委托中的运用,通过实例展示了如何利用类委托简化接口实现,以及如何借助标准与自定义属性委托管理属性的读写操作。通过`by`关键字的支持,Kotlin使得委托模式的实现更为直观且高效。
21 4
|
5天前
|
缓存 安全 Android开发
Android经典实战之用Kotlin泛型实现键值对缓存
本文介绍了Kotlin中泛型的基础知识与实际应用。泛型能提升代码的重用性、类型安全及可读性。文中详细解释了泛型的基本语法、泛型函数、泛型约束以及协变和逆变的概念,并通过一个数据缓存系统的实例展示了泛型的强大功能。
14 2
|
2天前
|
设计模式 Java Android开发
探索安卓应用开发:从新手到专家的旅程探索iOS开发中的SwiftUI框架
【8月更文挑战第29天】本文旨在通过一个易于理解的旅程比喻,带领读者深入探讨安卓应用开发的各个方面。我们将从基础概念入手,逐步过渡到高级技术,最后讨论如何维护和推广你的应用。无论你是编程新手还是有经验的开发者,这篇文章都将为你提供有价值的见解和实用的代码示例。让我们一起开始这段激动人心的旅程吧!
|
2天前
|
算法 安全 数据安全/隐私保护
Android经典实战之常见的移动端加密算法和用kotlin进行AES-256加密和解密
本文介绍了移动端开发中常用的数据加密算法,包括对称加密(如 AES 和 DES)、非对称加密(如 RSA)、散列算法(如 SHA-256 和 MD5)及消息认证码(如 HMAC)。重点讲解了如何使用 Kotlin 实现 AES-256 的加密和解密,并提供了详细的代码示例。通过生成密钥、加密和解密数据等步骤,展示了如何在 Kotlin 项目中实现数据的安全加密。
30 1
|
2天前
|
存储 算法 Java
Java中的集合框架深度解析云上守护:云计算与网络安全的协同进化
【8月更文挑战第29天】在Java的世界中,集合框架是数据结构的代言人。它不仅让数据存储变得优雅而高效,还为程序员提供了一套丰富的工具箱。本文将带你深入理解集合框架的设计哲学,探索其背后的原理,并分享一些实用的使用技巧。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇通往高效编程的大门。
|
3天前
|
算法 安全 数据安全/隐私保护
Android经典实战之常见的移动端加密算法和用kotlin进行AES-256加密和解密
本文介绍了移动端开发中常用的数据加密算法,包括对称加密(如 AES 和 DES)、非对称加密(如 RSA)、散列算法(如 SHA-256 和 MD5)及消息认证码(如 HMAC)。重点展示了如何使用 Kotlin 实现 AES-256 的加密和解密,提供了详细的代码示例。
12 2
|
3天前
|
Java 调度 Android开发
Android经典实战之Kotlin的delay函数和Java中的Thread.sleep有什么不同?
本文介绍了 Kotlin 中的 `delay` 函数与 Java 中 `Thread.sleep` 方法的区别。两者均可暂停代码执行,但 `delay` 适用于协程,非阻塞且高效;`Thread.sleep` 则阻塞当前线程。理解这些差异有助于提高程序效率与可读性。
16 1
|
3天前
|
Android开发
基于Amlogic 安卓9.0, 驱动简说(三):使用misc框架,让驱动更简单
如何使用Amlogic T972安卓9.0系统上的misc框架来简化驱动程序开发,通过misc框架自动分配设备号并创建设备文件,从而减少代码量并避免设备号冲突。
7 0
基于Amlogic 安卓9.0, 驱动简说(三):使用misc框架,让驱动更简单
|
10天前
|
Android开发 C++ 开发者
Android经典实战之跨平台开发方案:Kotlin Multiplatform vs Flutter
本文对比了Kotlin Multiplatform与Flutter两大跨平台开发框架,从技术特性、性能、开发效率、UI体验、可扩展性及适用场景等维度进行了详尽分析,帮助开发者根据项目需求和技术背景选择最优方案。
24 2
|
1天前
|
物联网 区块链 vr&ar
未来已来:探索区块链、物联网与虚拟现实技术的融合与应用安卓与iOS开发中的跨平台框架选择
【8月更文挑战第30天】在科技的巨轮下,新技术不断涌现,引领着社会进步。本文将聚焦于当前最前沿的技术——区块链、物联网和虚拟现实,探讨它们各自的发展趋势及其在未来可能的应用场景。我们将从这些技术的基本定义出发,逐步深入到它们的相互作用和集成应用,最后展望它们如何共同塑造一个全新的数字生态系统。
下一篇
云函数