Retrofit2 使用詳解

Retrofit 2 簡介

Retrofit是一個網(wǎng)絡(luò)訪問框架,和OkHttp同樣出自Square公司,Retrofit內(nèi)部依賴于OkHttp,但是功能上做了更多的擴展,比如返回結(jié)果的轉(zhuǎn)換功能,可以直接對返回數(shù)據(jù)進行處理。
在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)建訪問請求

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

創(chuàng)建請求時代碼如下:

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

GET注解表示方法為get,它接收一個字符串參數(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對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)建請求時的注解,分為三類:

  • 方法注解:
    用來設(shè)置請求方法,@GET、@POST、@PUT、@DELETE、@OPTIONS、@HTTP、@Headers。 除了常用的訪問方法之外,@HTTP可以設(shè)置任意方法。它包含三個參數(shù),method,path,和hasBody。@Headers用來設(shè)置請求頭,可以包含重復(fù)參數(shù),都會被保留下來。上文的例子使用@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();
  • 參數(shù)注解
    參數(shù)注解用來設(shè)置動態(tài)參數(shù),主要有@Url、@Query、@QueryMap、@Path、@Header,@Body、@Field、@FieldMap、@Part,@PartMap。
    首先看一下@Path和@Header,@Path用來設(shè)置路徑,輸入的內(nèi)容替換方法注解中的占位符,上文已經(jīng)展示過用法了。@Header用來動態(tài)設(shè)置請求頭:
@GET()
    Call<String>  setHeader(@Header("Accept") String acceptType);

@Query、@QueryMap用來設(shè)置請求參數(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進行網(wǎng)絡(luò)訪問。
其余的幾個注解@Body、@Field、@FieldMap、@Part,@PartMap,用在Post方法中設(shè)置參數(shù),下文會說明

  • 標記注解
    包括@FormUrlEncoded、@Multipart
    @FormUrlEncoded表示Post方法提交的是鍵值對數(shù)據(jù),對應(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方法對應(yīng)Content-Type: multipart/form-data,提交表單數(shù)據(jù)。對應(yīng)的參數(shù)注解為@Part,@PartMap。
除此之外還有json數(shù)據(jù),對應(yīng)參數(shù)注解@Body。

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

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

3.使用攔截器

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

處理Response

上面的例子中添加的是字符串的轉(zhuǎn)換器,得到的response.body()是簡單的字符串?,F(xiàn)在我們看一下Json是怎樣轉(zhuǎn)換的。
這里我們訪問的網(wǎng)址是 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();
}

開始網(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等等。當然也可以自己定義Converter,是繼承自Converter.Factory的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容