0
点赞
收藏
分享

微信扫一扫

Retrofit2 使用详解

芒果六斤半 2021-09-29 阅读 155

Retrofit 2 简介

Retrofit是一个网络访问框架,和OkHttp同样出自Square公司,Retrofit内部依赖于OkHttp,但是功能上做了更多的扩展,比如返回结果的转换功能,可以直接对返回数据进行处理。
在Android Studio中使用,先添加依赖:

使用方法

1.创建访问请求

不同于OkHttp,Retrofit采用接口和注解的方式来设置访问请求。比如访问本机的一个文件,地址如下:
http://192.168.1.102:8080/aaa.txt

创建请求时代码如下:

public interface ConnectService {
    @GET("aaa.txt")
    Call<String> getTxt();
}

GET注解表示方法为get,它接收一个字符串参数(aaa.txt)作为path,并且支持占位符写法:

public interface ConnectService {
    @GET("{name}")
    Call<String> getTxt(@Path("name") String name);
}

在这里,http://192.168.1.102:8080/作为BaseUrl,不需要在接口文件中定义,结尾的“/”,必须包含在BaseUrl中,注解中的路径不能以“/”开头。

Retrofit对Url的组合规则如下:

@GET("user1") + baseUrl("https://www.baidu.com/image/list/") = https://www.baidu.com/image/list/user1
@GET("user1") + baseUrl("https://www.baidu.com/image/list") = https://www.baidu.com/image/user1
@GET("/user1") + baseUrl("https://www.baidu.com/image/list") = https://www.baidu.com/user1

创建请求时的注解,分为三类:

  • 方法注解:
    用来设置请求方法,@GET、@POST、@PUT、@DELETE、@OPTIONS、@HTTP、@Headers。 除了常用的访问方法之外,@HTTP可以设置任意方法。它包含三个参数,method,path,和hasBody。@Headers用来设置请求头,可以包含重复参数,都会被保留下来。上文的例子使用@HTTP注解如下(添加了请求头,仅供参考):
    @Headers({
            "Accept: application/vnd.github.v3.full+json",
            "User-Agent: RetrofitBean-Sample-App",
    })
 @HTTP(method = "GET", path = "aaa.txt",hasBody = false)
    Call<String> getTxtHttp();
  • 参数注解
    参数注解用来设置动态参数,主要有@Url、@Query、@QueryMap、@Path、@Header,@Body、@Field、@FieldMap、@Part,@PartMap。
    首先看一下@Path和@Header,@Path用来设置路径,输入的内容替换方法注解中的占位符,上文已经展示过用法了。@Header用来动态设置请求头:
@GET()
    Call<String>  setHeader(@Header("Accept") String acceptType);

@Query、@QueryMap用来设置请求参数:

/\*https://api.heweather.com/x3/weather?cityid=CN101010300&key=035591c2b7*/
//使用@Query注解
    @GET("{version}/weather")
    Call<String> getWeather(@Path("version") String version, @Query("cityid") String id, @Query("key") String key);
//使用QueryMap注解
 @GET("{version}/weather")
    Call<String> getWeatherQueryMap(@Path("version") String version, @QueryMap Map<String, String> params);

@Url则用在非统一Url的情况下,可以接收参数作为Url进行网络访问。
其余的几个注解@Body、@Field、@FieldMap、@Part,@PartMap,用在Post方法中设置参数,下文会说明

  • 标记注解
    包括@FormUrlEncoded、@Multipart
    @FormUrlEncoded表示Post方法提交的是键值对数据,对应content-type=application/x-www-form-urlencoded。提交的内容由参数注解@Field、@FieldMap来设置。
@FormUrlEncoded
@POST("user/edit")
//@Field逐一设置
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
//@FieldMap统一设置
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@FieldMap Map<String,String> fieldMap);

@Multipart表示Post方法对应Content-Type: multipart/form-data,提交表单数据。对应的参数注解为@Part,@PartMap。
除此之外还有json数据,对应参数注解@Body。

2.访问网络
请求部分设置完成后,就可以进行网络访问了,使用方法类似于OkHttp:

//构建Retrofit对象,相当于OkHttpClient
        Retrofit retrofit = new Retrofit.Builder()
                //设置OKHttpClient,如果不设置会提供一个默认的
                .client(new OkHttpClient())
                //设置baseUrl
                .baseUrl("http://192.168.1.102:8080/")
                //添加字符串转换器
                .addConverterFactory(ScalarsConverterFactory.create())
                .build();
        //创建网络访问对象
        ConnectService cs = retrofit.create(ConnectService.class);
        //调用网络访问对象的方法,得到Call对象
        final Call<String> myCall = cs.getTxtHttp();
        //final Call<String> myCall = cs.getTxt("aaa.txt");
        //final Call<String> myCall = cs.getUrl("aaa.txt");
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Response<String>  response = myCall.execute();
                    String result = response.body().toString();
                    InputStream is = response.body().s
                    Log.d("retrofit", "同步返回: " + result);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        /*
        myCall.clone();
//异步方式
        myCall.enqueue(new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
                String result = response.body().toString();
                Log.d("retrofit", "异步返回: " + result);
            }
            @Override
            public void onFailure(Call<String> call, Throwable t) {
            }
        });*/

这里采用的是同步访问的方式,如果是异步,和okHttp一样,调用call.enqueue方法。需要注意的是,在Retrofit 2.0中异步访问的方式,onResponse总是会被调用。如果response不能被解析, response.body()返回null,其他的比如连接错误404等,也会调用onResponse,此时response.errorBody().string()可以获取错误信息。

3.使用拦截器

Retrofit是依赖于OkHttp的,使用拦截器的时候仍然依赖于OkHttpClient,需要先构建一个包含拦截器的OkHttpClient,然后传入到Retrofit中:

    class MyInterceptor implements Interceptor{
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Response response = chain.proceed(request);
            return response;
        }
    OkHttpClient okHttpClient = new OkHttpClient()
                .newBuilder()
                .addInterceptor(new MyInterceptor() )
                .build();
Retrofit retrofit = new Retrofit.Builder()
                //设置OKHttpClient,如果不设置会提供一个默认的
                .client(okHttpClient )
                .baseUrl("http://192.168.1.102:8080/")
                .addConverterFactory(ScalarsConverterFactory.create())
                .build();

处理Response

上面的例子中添加的是字符串的转换器,得到的response.body()是简单的字符串。现在我们看一下Json是怎样转换的。
这里我们访问的网址是 https://cdn.heweather.com/china-city-list.json 返回的是中国城市列表。

先用GsonFormat工具建立JavaBean文件CityEntity:

public class CityEntity {
    /**
     * id : CN101010100
     * cityEn : beijing
     * cityZh : 北京
     * countryCode : CN
     * countryEn : China
     * countryZh : 中国
     * provinceEn : beijing
     * provinceZh : 北京
     * leaderEn : beijing
     * leaderZh : 北京
     * lat : 39.904989
     * lon : 116.405285
     */
    private String id;
    private String cityEn;
    private String cityZh;
    private String countryCode;
    private String countryEn;
    private String countryZh;
    private String provinceEn;
    private String provinceZh;
    private String leaderEn;
    private String leaderZh;
    private String lat;
    private String lon;
    public String getId() {
        return 
    public void setId(String id) {
        this.id = id;
    }
    public String getCityEn() {
        return cityEn;
    }
    public void setCityEn(String cityEn) {
        this.cityEn = cityEn;
    }
    public String getCityZh() {
        return cityZh;
    }
    public void setCityZh(String cityZh) {
        this.cityZh = cityZh;
    }
    public String getCountryCode() {
        return countryCode;
    }
    public void setCountryCode(String countryCode) {
        this.countryCode = countryCode;
    }
   public String getCountryEn() {
        return countryEn;
    }
    public void setCountryEn(String countryEn) {
        this.countryEn = 
    public String getCountryZh() {
        return countryZh;
    }
    public void setCountryZh(String countryZh) {
        this.countryZh = countryZh;
    }
    public String getProvinceEn() {
        return provinceEn;
    }
    public void setProvinceEn(String provinceEn) {
        this.provinceEn = provinceEn;
    }
    public String getProvinceZh() {
        return provinceZh;
    }
    public void setProvinceZh(String provinceZh) {
        this.provinceZh = provinceZh;
    }
    public String getLeaderEn() {
        return 
    public void setLeaderEn(String leaderEn) {
        this.leaderEn = leaderEn;
    }
    public String getLeaderZh() {
        return leaderZh;
    }
    public void setLeaderZh(String leaderZh) {
        this.leaderZh = leaderZh;
    }
    public String getLat() {
        return lat;
    }
    public void setLat(String lat) {
        this.lat = lat;
    }
    public String getLon() {
        return lon;
    }
    public void setLon(String lon) {
        this.lon = lon;
    }
}

然后定义访问接口API:

public interface ConnectService {
    @GET("china-city-list.json")
    Call<List<com.cris.miniweather.model.CityEntity>> getCityList();
}

开始网络访问:

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://cdn.heweather.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        ConnectService cs = retrofit.create(ConnectService.class);
        final Call<List<com.cris.miniweather.model.CityEntity>> cityListCall = cs.getCityList();
        cityListCall.enqueue(new Callback<List<CityEntity>>(){
            @Override
            public void onResponse(Call<List<CityEntity>> call, Response<List<CityEntity>> response) {
                List<CityEntity> cityList = response.body();
                for (CityEntity cityEntity:cityList ){
                    Log.d("retrofit","City name is: " + cityEntity.getCityZh());
                }
            }
            @Override
            public void onFailure(Call<List<CityEntity>> call, Throwable t) {

            }
        });

关于Converter,Retrofit已经提供了Gson,Scalars等等。当然也可以自己定义Converter,是继承自Converter.Factory的。

举报

相关推荐

0 条评论