Android Retrofit2(一)相关概念和基本使用

Retrofit是什么

retrofit是一个restful的http网络请求框架的封装,但网络请求不是由retrofit来完成的,它只是封装了请求参数、header、url、返回结果等信息,而真正处理网络请求的是由OkHttp来完成的。

基础使用

  • 1、导包
//网络请求相关 implementation
"com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion"
       implementation "com.squareup.retrofit2:retrofit-
mock:$rootProject.retrofitVersion"
       implementation "com.squareup.retrofit2:converter-
gson:$rootProject.retrofitVersion"
       implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0'
       implementation "com.squareup.retrofit2:converter-
scalars:$rootProject.retrofitVersion"
       implementation "com.squareup.retrofit2:adapter-
rxjava2:$rootProject.retrofitVersion"
       implementation "com.squareup.retrofit2:converter-
gson:$rootProject.retrofitVersion"
  • 2、定义一个Http API接口类

interface WanAndroidApi {
   @GET("project/tree/json")
    Call<ProjectBean> getProject();
}
  • 3、使用Retrofit类生成WanAndroidApi 接口实现
Retrofit retrofit = new Retrofit.Builder()//建造者模式 .baseUrl("https://www.wanandroid.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        WanAndroidApi wanAndroidApi =
retrofit.create(WanAndroidApi.class);//代理实例
  • 4、发送HTTP请求,返回Response可以同步或者异步处理
Call<ProjectBean> call = wanAndroidApi.getProject();//获取具体的某个业务 //同步请求
Response<ProjectBean> response = call.execute();
ProjectBean projectBean = response.body();
//异步请求
call.enqueue(new Callback<ProjectBean>() {
@Override
            public void onResponse(final Call<ProjectBean> call, final
Response<ProjectBean> response) {
                Log.i("Zero","response: " + response.body());
            }
@Override
            public void onFailure(final Call<ProjectBean> call, final
Throwable t) {}
});

我们知道retrofit是通过注解配置请求的,在源码里我们可以看到一共有26个注解,我们最常用的肯定是GET和POST注解了。

/** Make a GET request. */
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface GET {
  /**
   * A relative or absolute path, or full URL of the endpoint. This value is optional if the first
   * parameter of the method is annotated with {@link Url @Url}.
   *
   * <p>See {@linkplain retrofit2.Retrofit.Builder#baseUrl(HttpUrl) base URL} for details of how
   * this is resolved against a base URL to create the full endpoint URL.
   */
  String value() default "";
}

在Retrofit中其实是通过注解 + 泛型 + 动态代理来实现的,并且其中使用了非常多的设计模式,具体我们在源码分析的时候再展开讲。我们回到GET注解:1、@Target(METHOD):代表是一个方法;@Target(PARAMETER):代表是一个参数,2、Retention(RUNTIME):并且是在运行期的注解。我们都知道运行期的注解,我们是需要通过反射获取他的内容的。在Retrofit中所有的26个注解都是运行期的注解。Retrofit在运行期的时候会去动态的解析标记上这些注解的内容。例如我们的GET注解,Retrofit在运行期的时候会去动态的解析标记上@GET,然后获取到"project/tree/json"这些值

interface WanAndroidApi {
   @GET("project/tree/json")
    Call<ProjectBean> getProject();
}

在retrofit中注解可以分成三类:1、请求方法类 2、标志类 3、参数类

1、请求方法类注解

image.png
  • 分别对应HTTP的请求方法
  • 接收一个字符串表示接口的path,与baseUrl组成完整的请求Url

其中我们需要注意的是HTTP注解,它是一个通用注解,可以替换以上所有的注解,其拥有method, path, hasBody三个属性。例如上面的get请求也可以这样写

 @GET("project/tree/json")
   fun getProject(): Call<ProjectBean>

 @HTTP(method = "get",path = "project/tree/json",hasBody = false)
   fun getProject(): Call<ResponseBody>

开发过后端接口的小伙伴看到这个肯定会觉得很熟悉,是不是和SpringBoot的写法很像,细心的小伙伴肯定也注意到了,顺带提一嘴,第一种Call里写的是ProjectBean,另外一种Call写了ResponseBody,其实这两种都可以,ResponseBody是更原始的方式,而你写了具体的实体类的话,retrofit会在内部帮你解析成ProjectBean,其实就是在你构建一个retrofit对象的时候.addConverterFactory(GsonConverterFactory.create())添加了这个GSON转化器,当然你觉得自己很牛逼想自己解析的话可以写成ResponseBody。转换器也是retrofit里很好用的东西,例如我们熟悉的GSON转化器,RxJava转化器,都可以在构建retrofit对象的时候添加进去。

2、参数类注解

image.png
  • Headers
 //使用 `@Headers`注解设置固定的请求头,不同的请求头不会相互覆盖,即使名字相同。
  @Headers("Cache-Control: max-age=640000")
@GET("project/list")
Call<ProjectBean> getMsg1();
@Headers({ "Accept: application/vnd.github.v3.full+json","User-Agent:
Retrofit-Sample-App"})
@GET("project/{username}")
Call<ProjectBean> getMsg2(@Path("username") String username);

需要注意的是,在Headers注解里,你可以传入多个Vlaue,源码里面是通过String数组接收的。

  • Header
    使用 @Header 注解动态更新请求头,匹配的参数必须提供给 @Header ,若参数值为 null ,这个头会 被省略,否则,会使用参数值的 toString 方法的返回值。
@GET("project")
Call<ProjectBean>getProject3(@Header("Authorization")String
   authorization);
  • Body
    使用 @Body 注解,指定一个对象作为 request body 。在使用post请求的时候会被用到。
@POST("project/new")
Call<ProjectBean> createProject(@Body ProjectBean user);
  • Field和FieldMap
 @FormUrlEncoded
    @POST("xxx")
    fun exmaple4(@Field("name") vararg name:String,
                 @Field("array") array: Array<String>,//name=xxx&age=22
                 @FieldMap map: Map<String,String>
                 ): Call<ResponseBody>
  • Path
  @GET("project/{id}/list")
    fun exmaple5(@Path("id") id: Int): Call<ResponseBody>
  • Query和QueryMap
 //http://www.xxx.xxx?name=sss&age=22
    @GET("xxxx")
    fun search(@Query("name") name: String,
               @QueryMap map: Map<String,String>): Call<ResponseBody>

Query和QueryMap是非常常用的,用于Get请求中指定参数

剩下的参数类注解都是用于表单字段的和Form表单请求一起讲。

3、 标志类注解

image.png
  • Streaming
    例如我们服务端返回给我们的图片是以流的方法返回的,我们就可以用到Streaming注解,我这里写个伪代码给大家看看Streaming的使用。
  @Streaming
    @GET
    Call<ProjectBean> downloadFile(@Url String fileUrl);

4、上传单个、多个文件

  • 单个文件
//第一种方法:RequestBody
 @Multipart
    @POST("project/upload")
    fun upload(@Part("file\";filename=\"test.png") file: RequestBody): Call<ResponseBody>

       //上传单个文件
        val file = File("")
        val requestBody = RequestBody.create(MediaType.parse("image/png"),file)

        val call = wanAndroidApi.upload(requestBody)

        call.enqueue(object : Callback<ResponseBody>{
            override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
            }

            override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
            }

        })

//第二种方法:MultipartBody.Part
 @Multipart
    @POST("project/upload")
    fun upload2(@Part file: MultipartBody.Part): Call<RequestBody>

  val file = File("")
        val requestBody = RequestBody.create(MediaType.parse("image/png"),file)
        val filePart =  MultipartBody.Part.createFormData("上传的key",
            file.name,requestBody)
        val call = wanAndroidApi.upload2(filePart)
        call.execute()//我这里为了演示,其实是要异步的

  • 多个文件
//第一种方法:RequestBody
 @Multipart
    @POST("project/upload")
    fun upload3(@PartMap map: Map<String,RequestBody>): Call<RequestBody>

 //图片集合
        val files = listOf<File>()
        val map = mutableMapOf<String,RequestBody>()
        files.forEach() {file ->
            val requestBody = RequestBody.create(MediaType.parse("image/png"),file)
            map["file\";filename=\"test.png"] = requestBody
        }
        wanAndroidApi.upload3(map)

//第二种方法:MultipartBody.Part
 @Multipart
    @POST("project/upload")
    fun upload4(@PartMap map: Map<String,MultipartBody.Part>): Call<RequestBody>

 val files = listOf<File>()
        val map = mutableMapOf<String,MultipartBody.Part>()
        files.forEachIndexed { index, file ->
            val requestBody = RequestBody.create(MediaType.parse("image/png"),file)
            val part = MultipartBody.Part.createFormData("上传的key${index}",file.name,requestBody)
            map["上传的key${index}"] = part
        }
        wanAndroidApi.upload4(map)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,829评论 1 331
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,603评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,846评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,600评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,780评论 3 272
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,695评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,136评论 2 293
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,862评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,453评论 0 229
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,942评论 2 233
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,347评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,790评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,293评论 3 221
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,839评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,448评论 0 181
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,564评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,623评论 2 249