Retrofit 2.X 的基本使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gaolh89/article/details/80796792

前沿

Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit底层基于OkHttp实现的.与其他网络框架不同的是,它更多使用运行时注解的方式提供功能.

使用前准备

先配置build.gradle:

//Retrofit联网框架
implementation 'com.squareup.retrofit2:retrofit:2.3.0'

//如果用到gson解析 需要添加下面的依赖
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'

//ConverterFactory的String依赖包
implementation  'com.squareup.retrofit2:converter-scalars:2.3.0'

上述最后2个依赖包是为了增加支持返回值为Gson/String 类型数据所添加的.如果想添加其他类型的支持,可以添加如下依赖包.

  • Jackson: com.squareup.retrofit2:converter-jackson
  • Moshi: com.squareup.retrofit2:converter-moshi
  • Protobuf: com.squareup.retrofit2:converter-protobuf
  • Wire: com.squareup.retrofit2:converter-wire
  • Simple XML: com.squareup.retrofit2:converter-simplexml

其中Gson、String类型最常见.

另外,需要注意的是,由于Retrofit 2.X 是网络请求,别网络在manifest加入访问网络的权限.

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

Retrofit 的注解分类

与其他请求框架不同的是, 它使用了注解.Retrofit 的注解分为三大类,分别是HTTP请求方法注解、标记类注解和参数类注解。
其中,HTTP 请求方法往解有8种,它们是GET、POST、PUT、DELETE、HEAD、PATCH、OPTIONS 和HTTP.其前7种分别对应HTTP的请求方法;HTTP则可以替换以上7种,也可以扩展请求方法。
标记类注解有3种,它们是FormUrlEnocoded、Mutipart、Streaming。 FormUrlEnocoded和Multipart 后面会讲到。Streaming代表响应的数据以流的形式返回,如果不使用它,则默认会把全部数据加载到内存,所以下大文件时需要加上这个注解。
参数类注解有Header、Headers、Body、Path、Field、FieldMap、Part、Query 和QueryMap等,下面将介绍几种参数类注解的用法。

Get请求访问网络

我们以淘宝的一个链接: http://ip.taobao.com/service/getIpInfo.php?ip=59.108.54.37 进行学习.
其中实体类代码如下:

IpModel 类

public class IpModel {

    private int    code;
    private IpData data;

    public void setCode(int code) {
        this.code = code;
    }

    public int getCode() {
        return this.code;
    }

    public void setData(IpData data) {
        this.data = data;
    }

    public IpData getData() {
        return this.data;
    }
}

IpData类:

 private String country;

    private String country_id;

    private String area;

    private String area_id;

    private String region;

    private String region_id;

    private String city;

    private String city_id;

    private String county;

    private String county_id;

    private String isp;

    private String isp_id;

    private String ip;

    public void setCountry(String country) {
        this.country = country;
    }

    public String getCountry() {
        return this.country;
    }

    public void setCountry_id(String country_id) {
        this.country_id = country_id;
    }

    public String getCountry_id() {
        return this.country_id;
    }

    public void setArea(String area) {
        this.area = area;
    }

    public String getArea() {
        return this.area;
    }

    public void setArea_id(String area_id) {
        this.area_id = area_id;
    }

    public String getArea_id() {
        return this.area_id;
    }

    public void setRegion(String region) {
        this.region = region;
    }

    public String getRegion() {
        return this.region;
    }

    public void setRegion_id(String region_id) {
        this.region_id = region_id;
    }

    public String getRegion_id() {
        return this.region_id;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getCity() {
        return this.city;
    }

    public void setCity_id(String city_id) {
        this.city_id = city_id;
    }

    public String getCity_id() {
        return this.city_id;
    }

    public void setCounty(String county) {
        this.county = county;
    }

    public String getCounty() {
        return this.county;
    }

    public void setCounty_id(String county_id) {
        this.county_id = county_id;
    }

    public String getCounty_id() {
        return this.county_id;
    }

    public void setIsp(String isp) {
        this.isp = isp;
    }

    public String getIsp() {
        return this.isp;
    }

    public void setIsp_id(String isp_id) {
        this.isp_id = isp_id;
    }

    public String getIsp_id() {
        return this.isp_id;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public String getIp() {
        return this.ip;
    }

1.直接使用

如果是直接执行@GET注解,代码如下:

 @GET("getIpInfo.php?ip=59.108.54.37")
    Call<IpModel> getIpMsg();

Retrofit提供的请求方式注解有@GET和@POST等,分别代表GET请求和POST请求,我们在这里用的是GET请求,访问的地址是”getIpInfo.php?ip=59.108.54.37”。另外定义了getlpMsg方法,这个方法返回 Call类型的参数。接下来创建Retrofit,并创建接口文件,代码如下所示:

扫描二维码关注公众号,回复: 6436975 查看本文章
String url = "http://ip.taobao.com/service/";
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        IpService ipService = retrofit.create(IpService.class);
        Call<IpModel> call = ipService.getIpMsg();

Retrofit是通过构造者模式构建出来的.请求URL是拼接而成的,它由baseUrl传入的URL加上请求网络接口的@GET(“getIpInfo.php?ip=59.108.54.37”)中的URL拼接而成的.接下来用Retrofit动态代理获取到之前定义的接口,并调用该接口定义的getIpMsg 方法得到Call对象.接下来用Call请求网络并处理回调.代码如下所示:

call.enqueue(new Callback<IpModel>() {
            @Override
            public void onResponse(Call<IpModel> call, Response<IpModel> response) {
                String country = response.body().getData().getCountry();
                Log.i("gaoleihua", "country" + country);
                Toast.makeText(MainActivity.this, country, Toast.LENGTH_SHORT).show();
            }

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

这里是异步请求网络,回调的Calbak是运行在UI线程的。得到返回的Response 后将返回数据的country字段用Toast显示出来。如果想同步请求网络,请使用all.execute(); 如果想中断网络请求,则可以使用call.cancel().

2.动态配置URL地址:@path

Retrofit提供了很多请求参数注解,这使得请求网路时更加便捷。其中,@Path用来动态地配置URL地址。请求网络接口代码如下所示:

@GET("{path}/getIpInfo.php?ip=59.108.54.37")
Call<IpModel> getIpMsg(@Path("path") String path);

在GET注解中包含了{path},它对应着@Path 注解中的”path”,而用来替换{path}的正是
要传入的”String path”的值。请求网络的代码如下所示:

 String url = "http://ip.taobao.com/";
 Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(url)
        .addConverterFactory(GsonConverterFactory.create())
        .build();

 IpServiceForPath ipService = retrofit.create(IpServiceForPath.class);
 Call<IpModel> call = ipService.getIpMsg(path);

 call.enqueue(new Callback<IpModel>() {
            @Override
            public void onResponse(Call<IpModel> call, Response<IpModel> response) {
                String country = response.body().getData().getCountry();
                Log.i("gaoleihua", "country" + country);
                Toast.makeText(MainActivity.this, country, Toast.LENGTH_SHORT).show();
            }

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

其中 通过传入 “service” 来替换@GET注解中的{path}的值.

整个完整的url拼接之后,依旧是 http://ip.taobao.com/service/getIpInfo.php?ip=59.108.54.37

3.动态指定查询条件:@Query

之前的例子就是为了查询ip的地址位置,每次查询更换不同的ip就可以了,可以使用@Query来动态地指定ip的值.请求网络接口的代码如下所示:

 @GET("getIpInfo.php")
 Call<IpModel> getIpMsg(@Query("ip") String ip);

请求网络时,只需要传入想要查询的ip值就可以了.

4.动态指定查询条件组:@QueryMap

在网络请求中一般为了更精确地查找我们所需要的数据,需要传入很多查询参数,如果用@Query会比较麻烦,这时我们可以采用@QueryMap,将所有的参数集成在一个Map中统一传递,如下所示:

@GET("getIpInfo.php")
Call<IpModel> getIpMsg(@QueryMap Map<String, String> options);

Post请求访问网络

1.传递数据类型为键值对:@Filed

传递数据类型为键值对,这是我们最常用的POST请求数据类型,淘宝IP库支持数据类型为键值对的POST请求.请求网络接口的代码如下所示:

 @FormUrlEncoded
 @POST("getIpInfo.php")
 Call<IpModel> getIpMsg(@Field("ip") String first);

首先用@FormUrlEncoded注释来标明这是一个表单请求,然后在getIpMsg方法中使用@Field(“ip”)注解来标识所对应的String类型数据的键,从而组成一组键值对进行传递.请求网络的代码如下所示:

        String url = "http://ip.taobao.com/service/";
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        IpServiceForPost ipService = retrofit.create(IpServiceForPost.class);
        Call<IpModel> call = ipService.getIpMsg(ip);
        call.enqueue(new Callback<IpModel>() {
            @Override
            public void onResponse(Call<IpModel> call, Response<IpModel> response) {
                String country = response.body().getData().getCountry();
                Log.i("gaoleihua", "country" + country);
                Toast.makeText(MainActivity.this, country, Toast.LENGTH_SHORT).show();
            }

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

2.传递数据类型JSON字符串:@Body

这个在使用开发中使用得很少.
我们也可以用POST方式将JSON字符串作为请求体发送到服务器.
用@Body这个注解标识参数对象即可,Retrofit会将对象转换为字符串

3.单个文件上传:@Part

public interface UploadFileForPart {  
    @Multipart
    @POST("user/photo")
    Call<User> updataUser(@PartMultipartBody.Part photo,@Part("description") 
    RequestBody description);
}

Multipart注解标识允许多个@Part. updataUser方法的第一个参数是准备上传的图片文件,使用了PartMultipartBody.Part 类型;另一个参数是RequestBody类型,它用来传递简单的键值对.

File file=new File(Environment.getExternalStorageDirectory(),"gaoleihua.png");

RequestBody photoRequestBody=RequestBody.create(MediaType.parse("image/png"),file);

MultipartBody.Part photo=MultipartBody.Part.createFormData("photos","gaoleihua.png",photoRequestBody);

UploadFileForPart uploadFileForPart=retrofit.create(UploadFileForPart.class);

Call<User> call=uploadFileForPart.updataUser(photo,RequestBody.create(null,"gaoleihua"));

4.多个文件上传:@PartMap

public interface UploadFileForPart {  
    @Multipart
    @POST("user/photo")
    Call<User> updataUser(@PartMap Map<String,RequestBody>photos,@Part("description") 
    RequestBody description);
}

这和单文件上传是类似的,只是使用Map封装了上传的文件,并用@PartMap 注解来标识起来.其他的和单文件上传都一样,这里就不赘述了.

消息报头Header

在HTTP请求中,为了防止攻击或过滤掉不安全的访问,或者添加特殊加密的访问等,以便减轻服务器的压力和保证请求的安全,通常都会在消息报头中携带一些特殊的消息头处理.Retrofit也提供了@Header 来添加消息报头。添加消息报头有两种方式。一种是静态的,另一种是动态的.

下面先来看静态的方式,如下所示:

interface SomeService{
@GET ("some/endpoint")
@Headers ("Accept一Encoding: application/json")
Call<ResponseBody> getCarType();
}

使用@Headers注解添加消息报头。如果想要添加多个消息报头,则可以使用{}包含起来:

interface SomeService {
@GET ("some/endpoint")
@Headers ({"Accept -Encoding:application/json",
"User- Agent:MoonRetrofit"
})

Call<ResponseBody> getCarType();
}

以动态的方式添加消息报头如下所示:

interface SomeService {
@GET ("some/endpoint")
Call<ResponseBody> getCarType(
@Header ("Location") String location)
);
}

使用@Header注释,可以通过调用getCarType方法来动态地添加消息报头.


源码

欢迎star,您的鼓励是我写作最大的动力.

点击跳转下载

猜你喜欢

转载自blog.csdn.net/gaolh89/article/details/80796792
今日推荐