Retrofit2 使用詳解

Retrofit 2 簡(jiǎn)介

Retrofit是一個(gè)網(wǎng)絡(luò)訪問框架蟆盹,和OkHttp同樣出自Square公司斥季,Retrofit內(nèi)部依賴于OkHttp,但是功能上做了更多的擴(kuò)展,比如返回結(jié)果的轉(zhuǎn)換功能,可以直接對(duì)返回?cái)?shù)據(jù)進(jìn)行處理我磁。
在Android Studio中使用圃阳,先添加依賴:

compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0' //json轉(zhuǎn)換
compile 'com.squareup.retrofit2:converter-scalars:2.3.0'//String 類型轉(zhuǎn)換

使用方法

1.創(chuàng)建訪問請(qǐng)求

不同于OkHttp厌衔,Retrofit采用接口和注解的方式來設(shè)置訪問請(qǐng)求。比如訪問本機(jī)的一個(gè)文件捍岳,地址如下:
http://192.168.1.102:8080/aaa.txt

創(chuàng)建請(qǐng)求時(shí)代碼如下:

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

GET注解表示方法為get富寿,它接收一個(gè)字符串參數(shù)(aaa.txt)作為path睬隶,并且支持占位符寫法:

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

在這里,http://192.168.1.102:8080/作為BaseUrl页徐,不需要在接口文件中定義苏潜,結(jié)尾的“/”,必須包含在BaseUrl中变勇,注解中的路徑不能以“/”開頭恤左。

Retrofit對(duì)Url的組合規(guī)則如下:

@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

創(chuàng)建請(qǐng)求時(shí)的注解,分為三類:

  • 方法注解:
    用來設(shè)置請(qǐng)求方法搀绣,@GET飞袋、@POST、@PUT链患、@DELETE巧鸭、@OPTIONS、@HTTP麻捻、@Headers纲仍。 除了常用的訪問方法之外,@HTTP可以設(shè)置任意方法芯肤。它包含三個(gè)參數(shù)巷折,method,path崖咨,和hasBody锻拘。@Headers用來設(shè)置請(qǐng)求頭,可以包含重復(fù)參數(shù)击蹲,都會(huì)被保留下來署拟。上文的例子使用@HTTP注解如下(添加了請(qǐng)求頭,僅供參考):
    @Headers({
            "Accept: application/vnd.github.v3.full+json",
            "User-Agent: RetrofitBean-Sample-App",
    })
 @HTTP(method = "GET", path = "aaa.txt",hasBody = false)
    Call<String> getTxtHttp();
  • 參數(shù)注解
    參數(shù)注解用來設(shè)置動(dòng)態(tài)參數(shù)歌豺,主要有@Url推穷、@Query、@QueryMap类咧、@Path馒铃、@Header,@Body痕惋、@Field区宇、@FieldMap、@Part值戳,@PartMap议谷。
    首先看一下@Path和@Header,@Path用來設(shè)置路徑堕虹,輸入的內(nèi)容替換方法注解中的占位符卧晓,上文已經(jīng)展示過用法了芬首。@Header用來動(dòng)態(tài)設(shè)置請(qǐng)求頭:
@GET()
    Call<String>  setHeader(@Header("Accept") String acceptType);

@Query、@QueryMap用來設(shè)置請(qǐng)求參數(shù):

/\*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則用在非統(tǒng)一Url的情況下逼裆,可以接收參數(shù)作為Url進(jìn)行網(wǎng)絡(luò)訪問郁稍。
其余的幾個(gè)注解@Body、@Field波附、@FieldMap艺晴、@Part,@PartMap掸屡,用在Post方法中設(shè)置參數(shù)封寞,下文會(huì)說明

  • 標(biāo)記注解
    包括@FormUrlEncoded、@Multipart
    @FormUrlEncoded表示Post方法提交的是鍵值對(duì)數(shù)據(jù)仅财,對(duì)應(yīng)content-type=application/x-www-form-urlencoded狈究。提交的內(nèi)容由參數(shù)注解@Field、@FieldMap來設(shè)置盏求。
@FormUrlEncoded
@POST("user/edit")
//@Field逐一設(shè)置
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
//@FieldMap統(tǒng)一設(shè)置
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@FieldMap Map<String,String> fieldMap);

@Multipart表示Post方法對(duì)應(yīng)Content-Type: multipart/form-data抖锥,提交表單數(shù)據(jù)。對(duì)應(yīng)的參數(shù)注解為@Part碎罚,@PartMap磅废。
除此之外還有json數(shù)據(jù),對(duì)應(yīng)參數(shù)注解@Body荆烈。

2.訪問網(wǎng)絡(luò)
請(qǐng)求部分設(shè)置完成后拯勉,就可以進(jìn)行網(wǎng)絡(luò)訪問了,使用方法類似于OkHttp:

//構(gòu)建Retrofit對(duì)象憔购,相當(dāng)于OkHttpClient
        Retrofit retrofit = new Retrofit.Builder()
                //設(shè)置OKHttpClient,如果不設(shè)置會(huì)提供一個(gè)默認(rèn)的
                .client(new OkHttpClient())
                //設(shè)置baseUrl
                .baseUrl("http://192.168.1.102:8080/")
                //添加字符串轉(zhuǎn)換器
                .addConverterFactory(ScalarsConverterFactory.create())
                .build();
        //創(chuàng)建網(wǎng)絡(luò)訪問對(duì)象
        ConnectService cs = retrofit.create(ConnectService.class);
        //調(diào)用網(wǎng)絡(luò)訪問對(duì)象的方法宫峦,得到Call對(duì)象
        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一樣导绷,調(diào)用call.enqueue方法。需要注意的是屎飘,在Retrofit 2.0中異步訪問的方式妥曲,onResponse總是會(huì)被調(diào)用。如果response不能被解析钦购, response.body()返回null檐盟,其他的比如連接錯(cuò)誤404等,也會(huì)調(diào)用onResponse肮雨,此時(shí)response.errorBody().string()可以獲取錯(cuò)誤信息。

3.使用攔截器

Retrofit是依賴于OkHttp的箱玷,使用攔截器的時(shí)候仍然依賴于OkHttpClient怨规,需要先構(gòu)建一個(gè)包含攔截器的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()
                //設(shè)置OKHttpClient,如果不設(shè)置會(huì)提供一個(gè)默認(rèn)的
                .client(okHttpClient )
                .baseUrl("http://192.168.1.102:8080/")
                .addConverterFactory(ScalarsConverterFactory.create())
                .build();

處理Response

上面的例子中添加的是字符串的轉(zhuǎn)換器,得到的response.body()是簡(jiǎn)單的字符串〔ǚ幔現(xiàn)在我們看一下Json是怎樣轉(zhuǎn)換的壳坪。
這里我們?cè)L問的網(wǎng)址是 https://cdn.heweather.com/china-city-list.json 返回的是中國(guó)城市列表。

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

public class CityEntity {
    /**
     * id : CN101010100
     * cityEn : beijing
     * cityZh : 北京
     * countryCode : CN
     * countryEn : China
     * countryZh : 中國(guó)
     * 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();
}

開始網(wǎng)絡(luò)訪問:

        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) {

            }
        });

關(guān)于Converter掰烟,Retrofit已經(jīng)提供了Gson爽蝴,Scalars等等。當(dāng)然也可以自己定義Converter纫骑,是繼承自Converter.Factory的蝎亚。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市先馆,隨后出現(xiàn)的幾起案子发框,更是在濱河造成了極大的恐慌,老刑警劉巖煤墙,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梅惯,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡仿野,警方通過查閱死者的電腦和手機(jī)铣减,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脚作,“玉大人葫哗,你說我怎么就攤上這事”钫恚” “怎么了魄梯?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)宾符。 經(jīng)常有香客問我酿秸,道長(zhǎng),這世上最難降的妖魔是什么魏烫? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任辣苏,我火速辦了婚禮,結(jié)果婚禮上哄褒,老公的妹妹穿的比我還像新娘稀蟋。我一直安慰自己,他們只是感情好呐赡,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布退客。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪萌狂。 梳的紋絲不亂的頭發(fā)上档玻,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音茫藏,去河邊找鬼误趴。 笑死,一個(gè)胖子當(dāng)著我的面吹牛务傲,可吹牛的內(nèi)容都是我干的凉当。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼售葡,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼看杭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起天通,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤泊窘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后像寒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烘豹,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年诺祸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了携悯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡筷笨,死狀恐怖憔鬼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情胃夏,我是刑警寧澤轴或,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站仰禀,受9級(jí)特大地震影響照雁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜答恶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一饺蚊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧悬嗓,春花似錦污呼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽籍凝。三九已至,卻和暖如春苗缩,著一層夾襖步出監(jiān)牢的瞬間静浴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工挤渐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人双絮。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓浴麻,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親囤攀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子软免,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Retrofit用法詳解 一、簡(jiǎn)介 Retrofit是Square公司開發(fā)的一款針對(duì)Android網(wǎng)絡(luò)請(qǐng)求的框架焚挠,...
    流水潺湲閱讀 847評(píng)論 0 6
  • 安卓開發(fā)領(lǐng)域中膏萧,很多重要的問題都有很好的開源解決方案,例如Square公司提供網(wǎng)絡(luò)請(qǐng)求 OkHttp , Retr...
    aaron688閱讀 1,905評(píng)論 1 20
  • 前言 如果看Retrofit的源碼會(huì)發(fā)現(xiàn)其實(shí)質(zhì)上就是對(duì)okHttp的封裝蝌衔,使用面向接口的方式進(jìn)行網(wǎng)絡(luò)請(qǐng)求榛泛,利用動(dòng)態(tài)...
    李某人吖閱讀 2,032評(píng)論 0 0
  • Retrofit 實(shí)際上并不能說是一個(gè)網(wǎng)絡(luò)請(qǐng)求框架,它其實(shí)是對(duì) okHttp 這個(gè)網(wǎng)絡(luò)請(qǐng)求框架在接口層面的封裝噩斟,網(wǎng)...
    EmanLu閱讀 1,036評(píng)論 0 2
  • 一曹锨、簡(jiǎn)介 Retrofit是Square公司開發(fā)的一款針對(duì)Android網(wǎng)絡(luò)請(qǐng)求的框架,Retrofit2底層基于...
    Devil不加V閱讀 540評(píng)論 0 0