前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android-Retrofit简介

Android-Retrofit简介

作者头像
android_薛之涛
发布2019-08-08 10:16:04
1.8K0
发布2019-08-08 10:16:04
举报
文章被收录于专栏:Android-薛之涛Android-薛之涛

上一篇文章讲了RxJava,这一篇当然就该讲Retrofit了,参考资料: https://blog.csdn.net/gumufuyun/article/details/83619879

1.Retrofit简介

Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装,网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责 网络请求接口的封装。在服务端返回数据之后,OkHttp 将原始的结果交给 Retrofit,Retrofit根据用户的需求对结果进行解析。

Retrofit 主要定义了 4 个接口:

  • Callback<T>:请求数据的返回;
  • Converter<F, T>:对返回数据进行解析,一般用 GSON ;
  • Call<T>:发送请求,Retrofit 默认的实现是 OkHttpCall<T>,也可以依需自定义 Call<T>;
  • CallAdapter<T>:将 Call 对象转换成其他对象,如转换成支持 RxJava 的 Observable对象

2.相关依赖

相关依赖:

代码语言:javascript
复制
//添加Retrofit依赖
    implementation 'com.squareup.retrofit2:retrofit:2.6.0'
    //用Gson解析json的转换器
    implementation 'com.squareup.retrofit2:converter-gson:2.0.2'

当然还有网络请求权限:

代码语言:javascript
复制
<uses-permission android:name="android.permission.INTERNET"/>

Retrofit将 Http请求 抽象成 Java接口:采用 注解 描述网络请求参数 和配置网络请求参数,用 动态代理 动态 将该接口的注解“翻译”成一个 Http的url请求,最后再执行 Http 请求。那我们先来解释Retrofit的各种注解吧。

3.注解类型

3.1网络请求方式的注解

网络请求中的网络请求方式的注解,如下:

  • 网络请求方式之@GET、@POST、@PUT、@DELETE、@HEAD 相关代码如下:
代码语言:javascript
复制
 //第一部分代码
    /**
     * 直接获得Responsebody中的内容,定义网络请求返回值为Call<ResponseBody>
     *  call<T> T是接受的数据返回类型
     */
    @GET("article/list/1/json")
    Call<ResponseBody> getCall();
//第二部分代码
Retrofit  retrofit = new Retrofit.Builder()
                 //设置网络请求的Url地址
                .baseUrl(baseUrl)
                 //设置数据解析器
                .addConverterFactory(GsonConverterFactory.create()).build();

由上图代码可以看到Rtrofit的封装请求url至少由两部分组成:baseUrl+@Get()中的内容动态拼接而成,但不是绝对的,也可以:

代码语言:javascript
复制
retrofit = new Retrofit.Builder()
                 //设置网络请求的Url地址
                .baseUrl("https://www.wanandroid.com/article/list/1/json")
                 //设置数据解析器
                .addConverterFactory(GsonConverterFactory.create()).build();

实际开发中不会这样写的,而且第一部分和第二部分的代码也是分开写的,我这里是为了演示方便,理解。 上面的代码也可以通过@Http这样写:

  • 网络请求方式之Http注解
代码语言:javascript
复制
/**
     * method 请求方法
     * path 请求路径,其中的{变量名}表示是一个变量
     * hasBody 是否有请求体
     * @param pageNum 参数
     * @return
     */
    @HTTP(method = "GET",path = "article/list/{pageNum}/json",hasBody = false)
    Call<ResponseBody> getCallData(@Path("pageNum") int pageNum);

@Http注解的作用和@GET,@Post作用一样,可替换@GET、@POST、@PUT、@DELETE、@HEAD注解且进行更多功能拓展。

3.2 标记
  • @FormUrlEncoded 使用场景:表示发送form-encoded的数据,那么什么是FormUrlEncoded数据呢?

image.png

每个键值对需要用@Filed来注解键名,随后的对象需要提供值。

代码语言:javascript
复制
/**
     * 表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
     * @param pageNum
     * @return
     */
    @GET("article/list/{pageNum}/json")
    @FormUrlEncoded
    Call<ResponseBody> getFormUrlEncodedData(@Field("pageNum") int pageNum );
  • @Multipart 使用场景: 作用:表示发送form-encoded的数据(适用于 有文件 上传的场景),也就是就是http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来表名文件类型;content-disposition,用来说明字段的一些信息;由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件。如图:

image.png

每个键值对需要用@Part来注解键名,随后的对象需要提供值。 代码:

代码语言:javascript
复制
  /**
     {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型
     * @param account 账号
     * @param pwd 密码
     * @param file file文件
     * @return
     */
    @GET("/form")
    @Multipart
    Call<ResponseBody> getMultipart(@Part("account") RequestBody account , @Part("pwd")
            RequestBody pwd, @Part MultipartBody.Part file);


    //具体执行代码:
    //既可以提交普通键值对,也可以提交(多个)文件键值对。
    public static final MediaType MEDIA_TYPE_MULTIPART_FORM = MediaType.parse("multipart/form-data;charset=utf-8");
    RequestBody account =RequestBody.create(MEDIA_TYPE_MULTIPART_FORM,"123");
    RequestBody pwd =RequestBody.create(MEDIA_TYPE_MULTIPART_FORM,"123");

    RequestBody fileResponseBody =RequestBody.create(MEDIA_TYPE_MULTIPART_FORM,"134646464");
    MultipartBody .Part file =MultipartBody.Part.createFormData("file","test.txt",fileResponseBody);

    Call<ResponseBody> call = (Call<ResponseBody>) getMultipart(account, pwd, file);
//同步请求
  Call<ResponseBody>  result =call .excute();
3.3 网络请求参数
  • @Header & @Headers 作用:添加请求头 &添加不固定的请求头 相关代码:
代码语言:javascript
复制
/ @Header
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
 
// @Headers
@Headers("Authorization: authorization")
@GET("user")
Call<User> getUser()
 
// 以上的效果是一致的。
// 区别在于使用场景和使用方式
// 1. 使用场景:@Header用于添加不固定的请求头,@Headers用于添加固定的请求头
// 2. 使用方式:@Header作用于方法的参数;@Headers作用于方法
  • Body 作用:以 Post方式 传递 自定义数据类型 给服务器 特别注意:如果提交的是一个Map,那么作用相当于 @Field 不过Map要经过 FormBody.Builder 类处理成为符合 Okhttp 格式的表单,如:
代码语言:javascript
复制
FormBody.Builder builder = new FormBody.Builder();
builder.add("key","value");
  • @Field & @FieldMap 作用:发送 Post请求 时提交请求的表单字段 具体使用:与 @FormUrlEncoded 注解配合使用
代码语言:javascript
复制
   /**
     * 表面明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
     * @param pageNum
     * @param pageSize
     * @return
     */
    @POST("/form")
    @FormUrlEncoded
    Call<ResponseBody> getFormUrlEncodedData(@Field("pageNum") int pageNum ,@Field("pageSize") int pageSize);

    /**
     * 表面明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
     * @param map
     * @return
     */
    @POST("/form")
    @FormUrlEncoded
    Call<ResponseBody> getFormUrlEncodedMap(@FieldMap Map<String, Object> map);

//具体执行代码:
       // @Field
        Call<ResponseBody> call1 =HttpRequest.getInstance().getInterfaceInstance().getFormUrlEncodedData(1,15);
        // @FieldMap
        // 实现的效果与上面相同,但要传入Map
        Map<String, Object> map = new HashMap<>();
        map.put("pageNum", 1);
        map.put("pageSize", 15);
        Call<ResponseBody> call2 = HttpRequest.getInstance().getInterfaceInstance().getFormUrlEncodedMap(map);
  • part & @PartMap 作用:发送 Post请求 时提交请求的表单字段 与@Field的区别:功能相同,但携带的参数类型更加丰富,包括数据流,所以适用于 有文件上传 的场景
  • @Query和@QueryMap 作用:用于 @GET 方法的查询参数(Query = Url 中 ‘?’ 后面的 key-value) 相关代码:
代码语言:javascript
复制
    /**
     * 登录接口
     * @param username 用户名
     * @param password 密码
     * @return
     */
    @POST("user/login")
    Observable<BaseResponse<LoginOutBean>> login(@Query("username") String username , @Query("password") String password);

其使用方式同 @Field与@FieldMap.

  • @Path 作用:URL地址的缺省值
  • @Url 作用:直接传入一个请求的 URL变量 用于URL设置,当有URL注解时,@GET传入的URL就可以省略。 4.实战操作

说了那么多不如来一个实战看看,这里以鸿洋大神的wanAndroid接口进行测试: 第一步定义请求接口类,用来管理所有的请求接口:

image.png

第二步:通过单例构建retrofit实例

代码语言:javascript
复制
public class HttpRequest {

    private static volatile HttpRequest httpRequest;
    private static String baseUrl = "https://www.wanandroid.com/";
    private static Retrofit retrofit;
    private static RequestInterface requestInterface;

    private HttpRequest() {
        //第二部分代码
        retrofit = new Retrofit.Builder()
                //设置网络请求的Url地址
                .baseUrl(baseUrl)
                //设置数据解析器
                .addConverterFactory(GsonConverterFactory.create()).build();
        //生成接口实例
        requestInterface = retrofit.create(RequestInterface.class);
    }

    public static HttpRequest getInstance() {
        if (httpRequest == null) {
            synchronized (HttpRequest.class) {
                if (httpRequest == null) {
                    httpRequest = new HttpRequest();
                }
            }
        }
        return httpRequest;
    }
    
    /**
     * 返回接口实例的方法
     *
     * @return
     */
    public RequestInterface getInterfaceInstance() {
        return requestInterface;
    }
    
}

第三步:执行相关请求

代码语言:javascript
复制
btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //调用方法  返回Call对象
                Call<ResponseBody> call = HttpRequest.getInstance().getInterfaceInstance().getCall(1);
                //call对象执行异步请求,访问网络
                call.enqueue(new Callback<ResponseBody>() {
                    @Override
                    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                        String jsonString = null;
                        try {
                             jsonString =new String((response.body()).bytes());
                            //再使用Retrofit自带的Gson去解析
                            PageBean pageBean = new Gson().fromJson(jsonString, PageBean.class);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        Toast.makeText(MainActivity.this,jsonString,Toast.LENGTH_LONG).show();

                    }

                    @Override
                    public void onFailure(Call<ResponseBody> call, Throwable t) {
                        Toast.makeText(MainActivity.this,t.getMessage(),Toast.LENGTH_LONG).show();
                    }
                });
            }
        });

简单就说这么多,如果你想更深的了解retrofit的源码,推荐文章:Retrofit想用得好就得这么死磕。 完毕!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019.08.07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.Retrofit简介
  • 2.相关依赖
  • 3.注解类型
    • 3.1网络请求方式的注解
      • 3.2 标记
        • 3.3 网络请求参数
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档