Android开发之路—网络请求篇Retrofit2.0的使用

本文详细介绍Retrofit网络请求框架的使用方法,包括注解类型、依赖添加、接口描述、实例创建、同步异步请求、HTTPS请求及与Rxjava结合使用等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考文章:
https://blog.youkuaiyun.com/m0_37796683/article/details/90702095

欢迎关注我的个人公众号
在这里插入图片描述

一、前言

最近着实有点烦躁,疫情的影响,整个生活和工作都感觉到压抑。今天打算写一下Retrofit网络请求框架,之后的几篇打算把所有的网络框架都写一下,算是对网络请求框架的一个总结。

1、Retrofit是什么

Retrofit是一个RESTful的HTTP网络请求框架的封装,Retrofit的本质是通过注解的形式封装请求参数、Header、URL、返回值等信息。底层的请求工作时交给OkHttp完成的,Retrofit是本质上是对网络请求接口的封装。但是这种高度封装带来的后果就是扩展性差,解析的数据都是统一的converter,如果服务器不能给出统一的API形式,那么很难处理。但是这种缺点我们可以通过自定义converter来处理。

二、Retrofit注解类型

我们前面说过Retrofit是通过注解的方式对接口的统一封装,然后交给okhttp来完成网络请求。
Retrofit对网络请求接口的定义如下:

public interface APIInterface {
    //获取无重复ID
    @GET("tools/no_repeat_id/long")
    Call<ResponseBody> getLongId();
    }

这里APIInterface是所有网络请求的封装的Interface,getLongId为我们定义的请求方法名,注解@GET为get请求后面的参数代表请求的部分url,返回值类型为Call泛型为ResonseBody;
Retrofit的注解类型共有三种:

  1. 网络请求方法注解;
  2. 标记类注解;
  3. 网络请求参数注解

1、网络请求方法注解

有的博客还将@HEADER和@HEADERS单独划分出来作为请求头注解也是可以的。

注解名称说明
@GET采用Get方法发送网络请求
@POST采用Post方法发送网络请求
@PUT采用Put方法发送网络请求
@DELETE采用Delete方法发送网络请求
@PATCH该请求是对put请求的补充,用于更新局部资源
@HEADhead请求
@OPTIONSoptions请求
@HTTP通过注解,可以替换以上所有的注解,它拥有三个属性:method、path、hasBody

2、标记类注解

注解名称说明
@FromUrlEncoded发送编码表单数据请求,每个键值对需要使用@Filed注解
@Multipart表示发送form-encoded的数据(适用于有文件上传的场景)
@Streaming表示响应用字节流的形式返回,如果没有使用注解,默认会把数据全部载入到内存中,之后获取数据也是从内存中读取。

3、网络请求参数注解

注解名称说明
@Headers添加固定的请求头,作用于方法
@Header添加不固定的请求头,作用于方法的参数
@Body非表单请求体如:json
@Filed、@FiledMapPost表单请求字段,需要配合@FromUrlEncoded使用。体现在请求体上
@Part、@PartMap文件上传,表单字段
@Query、@QueryMapGet的请求参数字段,体现在URL上。
@Path用于URL中的占位符
@Url设置请求路径

以上的请求注解我们暂时仅做了解一下,接下来结合具体的例子能帮助我们理解。

三、Retrofit的使用方法

1、添加依赖

implementation ‘com.squareup.retrofit2:retrofit:2.7.2’

2、添加网络权限

3、创建用于描述网络接口的类

public interface APIInterface {
    //获取无重复ID
    @GET("tools/no_repeat_id/long")
    Call<ResponseBody> getLongId();
    
    }

4、创建Retrofit的实例

 mRetrofit=new Retrofit.Builder()
                .baseUrl(Configure.URL_OPEN)
               //支持自定义数据解析
                .addConverterFactory(GsonConverterFactory.create())
                .build();

说明:

  1. Retrofit的实例通过new Retrofit.Builder()创建,设置baseUrl,接口地址包含两个部分,一部分就是baseUrl,另一部分是APIInterface中定义的@GET注解接口方法名tools/no_repeat_id/long;这两部分就是一个完整的请求路径。
  2. 添加数据解析器Gson,如果不添加默认接受的是字符串类型。
  3. 注意baseUrl的地址必须以“/”结尾,否则会抛异常

设置Gson数据解析需要配置以下依赖:

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

5、创建网络接口请求示例

Call<ResponseBody>callGetID=mRetrofit.create(APIInterface.class)
                            .getLongId();

6、完成网络请求(同步、异步)

6.1、发送同步请求:

 new Thread(new Runnable() {
            @Override
            public void run() {
        try {
            Response<ResponseBody>mResponse=callGetID.execute();
            Log.d(TAG,mResponse.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();

同步请求调用execute()方法;

6.2、发送异步请求:

callGetID.getLongId().enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
            try {
                Log.d(TAG,response.body().string());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {
            Log.d(TAG,t.toString());
        }
    });

异步请求执行enqueue方法。

我们简单的介绍了如何使用@Get无参注解进行同步和异步的请求,前面我们也介绍了Retrofit中的注解类型,接下来我们具体看一下请求注解的使用。

7、请求注解的使用

7.1、Get请求注解的使用

get请求的无参请求,上面的例子我们已经给出了

7.1.1、无参请求
public interface APIInterface {
    //获取无重复ID
    @GET("tools/no_repeat_id/long")
    Call<ResponseBody> getLongId();
    
    }

说明:

  1. @GET(),get请求方法注解,括号内代表url中的路径和请求方法,注意不能以“/”结尾;否则会报错,这一点要与baseUrl区分;
  2. getLongId()是我们定义的请求方法,返回值类型为Call,入参为无参。
7.1.2、有参请求

Get有参请求注解中,分为参数个数固定的和参数不固定的,我们统一来看

 @GET("jokes/list")
 Call<ResponseBody> getJokes(@Query("page") String pageNum);

说明:
@Query是get请求中的请求参数注解,括号内的page就是我们的请求参数,它会拼接到@Get请求url的后面(拼接形式:baseurl+jokes/list?page=1),String 代表请求参数类型,pageNum请求参数的数值。

 @GET("music/order/song/list")
 Call<ResponseBody> getNewsList(@QueryMap Map<String,Object> map);

说明:@QueryMap是get请求参数不固定的注解,相当于多个@Query,请求方法接收一个Map,这个Map是用来对请求参数的封装。

7.2、 Post请求注解的使用

7.2.1、Post请求无参注解的使用

post请求无参注解和get请求无参注解类似,只不过将@GET注解改成@POST注解,示例代码如下:

//获取无重复ID
    @Post("tools/no_repeat_id/long")
    Call<ResponseBody> getLongId();
7.2.2、Post请求有参注解的使用(表单数据)
@FormUrlEncoded
@POST("user/login")
Call<ResponseBody> postLogin(@Field("username") String name,@Field("password") String pwd);

有参的post请求,针对form表单请求需要添加注解@FormUrlEncoded,表示表单请求的键值对进行了url编码,此外每个键的字段需要添加@Field注解。
这个是针对参数固定请求的写法,如果参数不固定,采用下面的写法。

@FormUrlEncoded
@POST("user/login")
Call<ResponseBody> postLogin(@FieldMap Map<String,String> map);

@FieldMap与@Field的作用一致,可以用于添加多个不确定的参数,类似@QueryMap;

7.2.3、Post请求有参注解非标单数据的使用

对于非表单数据的请求,通过@Body注解传递自定义的数据类型给服务器,表单注解@Body不能用于表单或者支持文件上传的表单的编码,即不能与@FormUrlEncoded和@Multipart注解同时使用

@POST("user/login")
Call<ResponseBody> postRegisterAccountBody(@Body RequestBody body)

使用方法:

FormBody.Builder builder = new FormBody.Builder();
builder.addEncoded("username","xuchangqing");
builder.addEncoded("password","Xcq12345");
builder.addEncoded("repassword","Xcq12345");

builder.build()作为RequestBody中body参数的使用。

7.3、请求头注解的使用

有时我们需要在网络请求中加入请求头,Retrofit提供了两种添加请求头的方式@Header添加不固定的请求头,@Headers添加固定的请求头。

 @GET("user/login")
 Call<ResponseBody> getHeaderData(@Header("token") String token);
 
 @Headers({"phone-type:android", "version:1.1.1"})
 @GET("user/login")
 Call<ResponseBody> getHeadersData();

说明:@Header作用于参数,@Headers作用于方法。

7.4、文件上传注解的使用

7.4.1、文件和参数混合上传注解的使用
@Multipart
@POST("user/picture")
Call<ResponseBody> getPartData(@Part("name") RequestBody name, @Part MultipartBody.Part file);

说明:@Multipart是一个支持文件上传的表单,但是需要配合@Part和@PartMap使用,@Part 支持三种类型的数据:一种是RequestBody类型,一种是MultipartBody.Part类型,另一种是任意数据类型;这里的网络接口是文件和请求参数混合上传的方式,第一个参数为请求参数,第二个参数为文件。

 //上传文字
MediaType mediaType = MediaType.parse("text/plain");
RequestBody fileName = RequestBody.create(mediaType, "xuchangqing");
//上传图片
File file = new File("");
MediaType mediaTypeImg = MediaType.parse("image/png");
RequestBody mFile = RequestBody.create(mediaTypeImg, file);

MultipartBody.Part muiltPart = MultipartBody.Part.createFormData("file", file.getName(), mFile);

7.4.2、单文件上传注解的使用
@Multipart
@POST("user/picture")
Call<ResponseBody> getPartData @Part MultipartBody.Part file);

//上传图片
File file = new File("");
MediaType mediaTypeImg = MediaType.parse("image/png");
RequestBody mFile = RequestBody.create(mediaTypeImg, file);

MultipartBody.Part muiltPart = MultipartBody.Part.createFormData("file", file.getName(), mFile);
7.4.3、多文件上传注解的使用
 @Multipart
 @POST("user/followers")
 Call<ResponseBody> getPartMapData(@PartMap Map<String, MultipartBody.Part> map);

注意:
在使用文件上传的过程中,如果我们采用这种写法

@Multipart
@POST("user/picture")
Call<ResponseBody> getPartData @Part("file") RequestBody file);

服务端识别不出这个是一个文件的,会把它当成一个参数;
另外MultipartBody.Part作为参数类型的话,@Part一定是无参的,否则会报错。

7.5、其他请求注解的使用

7.5.1、@Body注解的使用

前面我们说过@Body注解用于非表单形式的请求,如json,HashMap,自定义实体类等。它的用法:

 @POST("user/login")
 Call<UserBean> postUserLogin(@Body UserBean userBean);

我们传入的是一个实体类,当然我们要在retrofit中添加适配器GsonConverterFactory,这时UserBean会转成json发送到服务器中。注意:@Body注解不能用于表单或者支持文件上传的表单的编码,即不能与@FormUrlEncoded和@Multipart注解同时使用,否则会报错。

7.5.2、@HTTP注解的使用
@HTTP(method = "POST", path = "user/login", hasBody = false)
Call<ResponseBody> getHttpData();

@HTTP它拥有三个属性:method、path、hasBody,注意method的请求方法名要注意大小写,path代表请求路径,hasBody代表是否包含请求体。
@HTTP注解可以替代Get\Post\Delete请求;

7.5.3、@Path注解的使用

@Path注解用于Url中的占位符{},所有在网址中的参数,通过{}占位符来标记;

@GET("user/{id}")
Call<ResponseBody> getUserId(@Query("name")String userName, @Path("id")String id);
7.5.4、@Url注解的使用
@FormUrlEncoded
@POST
Call<ResponseBody> postRegisterAccountMap(@Url String url, @FieldMap Map<String, String> map);

注意如果有@Url注解时,@POST中的参数必须省略,否则报错。

7.5.5、@Streaming注解的使用

表示响应体的数据用流的方式返回,使用于返回数据比较大,该注解在下载大文件时特别有用

四、HTTPS请求方式

Https的请求为了保证数据在传输过程中更加的安全,采用SSL证书验证身份的一种请求方式。htpps认证分为单项认证和双项认证的方式;

4.1、单项认证

单项认证就是校验服务端是否具有合法性,这需要在客户端配置服务端的证书;客户端请求服务器的证书与客户端证书比对是否一致,如果不一致则认为是非法的服务端;

4.2、双项认证

双项认证主要是应用在安全等级要求比较高的领域比如银行金融等。双项认证不仅要求客户端校验服务端也同时要求服务端校验客户端。服务端校验客户端,需要客户端将证书传送给服务端进行校验。

4.3、注意

我们使用Https请求并没有配置SSL证书,为什么是成功的呢?这是因为我们Android系统中配置了CA的根证书或者是我们对Https请求没有进行证书校验,但是这么做假设不合法的服务器也配置了CA的证书,客户端也是能够校验通过的。对于客户端对https请求没有进行证书校验,有两种通用的做法:

  • 创建一个不验证证书链的证书信任管理器
 final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] chain,
                    String authType) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] chain,
                    String authType) throws CertificateException {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[0];
            }
        }};
  • 使用自定义SSLSocketFactory
private void onHttps(OkHttpClient.Builder builder) {
    try {
        builder.sslSocketFactory(getSSLSocketFactory()).hostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    } catch (Exception e) {
        e.printStackTrace();
    }

}

五、与Rxjava结合使用

与Rxjava的结合使用方式比较简单,如果对Rxjava的使用方法还不熟悉的同学可以看一下我上篇的Rxjva使用。

5.1、配置依赖

使用Rxjava需要我们配置添加依赖:

implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'

代码中添加依赖:
addCallAdapterFactory(RxJavaCallAdapterFactory.create())

mRetrofit=new Retrofit.Builder()
        .baseUrl(Configure.URL_OPEN)
       //支持自定义数据解析
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();

5.2、使用方法

Retrofit与Rxjava的结合使用方法, 需要我们在定义的接口中的返回值类型变更为Observable即可。
具体使用方法如下:

  1. 接口定义:
@POST("user/login")
@FormUrlEncoded
Observable<ResponseBody> postLoginObserve(@Field("username") String name, @Field("password") String pwd);

  1. 代码实现
Retrofit.Builder retrofitBuilder = new Retrofit.Builder();
    Retrofit retrofit = retrofitBuilder.baseUrl(Configure.URL_Android)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .build();
    retrofit.create(APIInterface.class)
            .postLoginObserve("xuchangqing","Xcq12345")
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Observer<ResponseBody>() {
                @Override
                public void onCompleted() {

                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onNext(ResponseBody responseBody) {
                    try {
                        Log.d(TAG,"Observer_____+"+responseBody.string());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });

六、问题

java.lang.IllegalArgumentException: baseUrl must end in /

解决办法:baseurl必须以"/"结尾;

java.lang.IllegalArgumentException: @Url cannot be used with @POST URL (parameter #1)
解决办法:@Post或者@Get的注解必须保证是不带路径的。不能写成@Post(“xx/xx”)或者@Get(“xx”)这种形式。

Observable 泛型不支持

解决办法:不要导入java.util的包,导入import rx.Observable;

引入rxjava无法识别AndroidSchedulers.maithread();
注意导包问题,可能Observable所在的包和RxAndroid所在的包名不一致;

七、 总结

这篇文章算是对Retrofit的基本使用做了简单的介绍,但是讲起如何进行封装,有时间打算说一下框架的封装及源码的实现。先说这么多,算是个总结吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值