Retrofit2 使用详解

Retrofit 2 简介

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

compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0' //json转换
compile 'com.squareup.retrofit2:converter-scalars:2.3.0'//String 类型转换

使用方法

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的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • Retrofit用法详解 一、简介 Retrofit是Square公司开发的一款针对Android网络请求的框架,...
    流水潺湲阅读 847评论 0 6
  • 安卓开发领域中,很多重要的问题都有很好的开源解决方案,例如Square公司提供网络请求 OkHttp , Retr...
    aaron688阅读 1,905评论 1 20
  • 前言 如果看Retrofit的源码会发现其实质上就是对okHttp的封装,使用面向接口的方式进行网络请求,利用动态...
    李某人吖阅读 2,035评论 0 0
  • Retrofit 实际上并不能说是一个网络请求框架,它其实是对 okHttp 这个网络请求框架在接口层面的封装,网...
    EmanLu阅读 1,036评论 0 2
  • 一、简介 Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于...
    Devil不加V阅读 544评论 0 0