Retrofit你想知道的一切之基礎(chǔ)使用

Retrofit--相信大家都或多或少的聽過和用過了,不知道是什么的證明你已經(jīng)out了~我使用和研究Retrofit也有一段時間了,所以準備記錄一下自己使用的一些成果。這篇將會介紹Retrofit的簡單配置和使用。
注:本系列Retrofit版本為2.1.0,OkHttp版本為3.4.1;本系列的接口均為非RESTful接口

Retrofit初識

1.HTTP請求方法和簡單的RESTful

Retrofit支持RESTful ,先來簡單的說一下RESTful接口(由于我自己也對RESTful一臉懵逼,所以請小伙伴們自行Google了解更多)。首先在這里先來說一下HTTP的請求方法,HTTP請求方法包含get、post、delete、put、head、patch、trace、options總共8種。除get外,其他6種都是基于post方法衍生的,最常見的是get和post,而put、delete、post、get這四種最重要,分別對應(yīng)數(shù)據(jù)庫的增刪改查。

我們先來看一下比較常見的接口地址:
對學(xué)生信息進行操作:1.查詢學(xué)生數(shù)量 2.創(chuàng)建新學(xué)生 3.修改學(xué)生信息 4.刪除學(xué)生。

請求方法 接口地址 接口說明
get /api/student/index 查詢接口
post /api/student/ + 參數(shù) 創(chuàng)建接口
post /api/student/update + 參數(shù) 修改接口
post /api/student/delete + 參數(shù) 刪除接口

而如果我們用了RESTful API就會變成這樣:

請求方法 接口地址 接口說明
get /api/student/index 查詢接口
post /api/student/ + 參數(shù) 創(chuàng)建接口
put /api/student/ + 參數(shù) 修改接口
delete /api/student/ + 參數(shù) 刪除接口

大家是不是也看出兩者的區(qū)別了?修改跟刪除直接用HTTP的請求方法(Method)來指定,雖然url 一樣,但仍然可以知道你的動作。這就是所謂的RESTful 概念(這部分出自百萬講師stormzhang,感謝張哥帶我們飛~)

2.開啟Retrofit旅程

導(dǎo)入Retrofit:

compile 'com.squareup.retrofit2:retrofit:2.1.0'

Retrofit通過接口來管理HTTP API,那么首先我們先定義一個API的接口:

public interface RetrofitApi{
    @GET("public")
    Call<BaseResult<User>>  getUser();
}

然后通過Retrofit.Builder獲取到Retrofit實例,并通過create(clazz)方法獲取到我們剛才創(chuàng)建的RetrofitApi接口實例:

Retrofit retrofit=new Retrofit.Builder()
        .baseUrl("http://192.168.1.79:8080/")
        .build();

RetrofitApi retrofitApi=retrofit.create(RetrofitApi.class);

有了RetrofitApi實例之后,我們就可以在需要網(wǎng)絡(luò)請求的地方調(diào)用了:

Call<BaseResult<User>> userCall=retrofitApi.getUser();

以上是利用Retrofit向http://192.168.1.79:8080/public接口發(fā)送一個get請求,獲取用戶信息。

注:baseUrl("")中的url必須以'/'結(jié)尾,否則會報異常;@GET("public")中的url如果是需要拼接在baseUrl之后的則不要以‘/’開頭

Retrofit的注解

Retrofit中有很多注解,這些注解總共分三類:HTTP請求方法、標記類、參數(shù)類

1.HTTP請求方法注解

Retrofit支持八種HTTP請求方法注解,分別是:GET,POST,PUT,DELETE,HEAD,PATCH,OPTIONS,HTTP,其中前7種分別對應(yīng)HTTP請求方法(見Retrofit初識小節(jié)1),而HTTP注解可自定義請求方法,也就是說可以替換前面七種方法。

  • GET:對應(yīng)HTTP的get請求方法

    寫法:

    @GET("public")
    Call<BaseResult<List<User>>> getUser();
    
  • POST:對應(yīng)HTTP的post請求方法

    寫法:

       @POST("User")
       Call<BaseResult<String>> addUser();
    
  • PUT:對應(yīng)HTTP的put請求方法

    寫法:

       @PUT("User")
       Call<BaseResult<String>> updateUser();
    
  • DELETE:對應(yīng)HTTP的delete請求方法

    寫法:

       @DELETE("User")
       Call<BaseResult<String>> deleteUser();
    
  • HEAD:對應(yīng)HTTP的head請求方法

  • PATCH:對應(yīng)HTTP的patch請求方法

  • OPTIONS:對應(yīng)HTTP的options請求方法

  • HTTP:可替換以上七種,也可以擴展請求方法

    寫法:

       /**
    * method 表示請的方法,不區(qū)分大小寫
    * path表示路徑
    * hasBody表示是否有請求體
    */
    @HTTP(method = "get", path = "public", hasBody = false)
    Call<BaseResult<List<User>>> getUser();
    

2.標記類注解

Retrofit支持三種標記類注解,分別是:FormUrlEncoded、Multipart、Streaming。

  • FormUrlEncoded:指請求體是一個Form表單,Content-Type=application/x-www-form-urlencoded,需要和參數(shù)類注解@Field@FieldMap搭配使用(詳見下節(jié))

    寫法:

    @FormUrlEncoded
    @POST("public")
    Call<BaseResult> addUser(@Field("userName") String userName);
    
  • Multipart:指請求體是一個支持文件上傳的Form表單,Content-Type=multipart/form-data,需要和參數(shù)類注解@Part@PartMap搭配使用(詳見下節(jié))

    寫法:

    @Multipart
    @POST("public")
    Call<BaseResult> uploadFile(@Part MultipartBody.Part file);
    
  • Streaming:指響應(yīng)體的數(shù)據(jù)以流的形式返回,如果不使用默認會把數(shù)據(jù)全部加載到內(nèi)存,所以下載文件時需要加上這個注解

    寫法:

    @Streaming
    @GET("download")
    Call<ResponseBody> downloadFile();
    

3.參數(shù)類注解

  • Headers:添加請求頭,作用于方法

    寫法:

    @Headers("Cache-Control: max-age=640000")
    @GET("public")
    Call<BaseResult<List<User>>> getUser();
    

    @Headers({
        "Cache-Control: max-age=640000"
        "User-Agent: Retrofit-Sample-App"
    })
    @GET("public")
    Call<BaseResult<List<User>>> getUser();
    

    ?

  • Header:用于動態(tài)添加頭部,作用于方法參數(shù)

    寫法:

    @GET("public")
    Call<BaseResult<List<User>>> getUser(@Header("Token") String token);
    
  • Body:用于非表單請求體,作用于方法參數(shù)

    寫法:

    @POST("user")
    Call<BaseResult<String>> addUser(@Body User user);
    
  • Url:用于動態(tài)改變Url,作用于方法參數(shù)

    寫法:

    @GET("public")
    Call<BaseResult<List<User>>> getUser(@Url String url);
    

    請求的時候,url會替換掉public

  • Path:用于替換請求地址,作用于方法參數(shù)

    寫法:

    @GET("{path}")
    Call<BaseResult<List<User>>> getUser(@Path("path") String path);
    
  • Field:用于表單字段參數(shù),(需要配合FormUrlEncoded使用)作用于方法參數(shù)

    寫法:

    @FormUrlEncoded
    @POST("public")
    Call<BaseResult> addUser(@Field("userName") String userName);
    
  • FieldMap:用于表單字段參數(shù),接收Map實現(xiàn)多個參數(shù),(需要配合FormUrlEncoded使用)作用于方法參數(shù)

    寫法:

    @FormUrlEncoded
    @POST("public")
    Call<BaseResult> addUser(@FieldMap Map<String,String> fieldMap);
    
  • Part:用于表單字段參數(shù),適用于文件上傳,(需要配合Multipart使用)作用于方法參數(shù)

    寫法:

    @Multipart
    @POST("public")
    Call<BaseResult> uploadFile(@Part MultipartBody.Part file);
    
  • PartMap:用于表單字段參數(shù),適用于文件上傳,(需要配合Multipart使用)作用于方法參數(shù)

    寫法:

    @Multipart
    @POST("public")
    Call<BaseResult> uploadFile(@PartMap Map<String,RequestBody> RequestBodyMap);
    
  • Query:用于條件字段參數(shù),作用于方法參數(shù)

    寫法:

    @GET("public")
    Call<BaseResult<List<User>>> getUser(@Query("userId") String userId);
    
  • QueryMap:用于條件字段參數(shù),作用于方法參數(shù)

    寫法:

    @GET("public")
    Call<BaseResult<List<User>>> getUser(@QueryMap Map<String,String> map);
    

注:如果使用Post請求方式,建議使用Field或FieldMap+FormUrlEncoded傳遞參數(shù),雖然Query或QueryMap也可以實現(xiàn),但是Query或QueryMap都是將參數(shù)拼接在url后面的,而@Field或@FieldMap傳遞的參數(shù)時放在請求體的

Retrofit的配置

1.為Retrofit添加Converter

Retrofit中提供了Converter的概念,直譯為轉(zhuǎn)換器,Retrofit正常請求下來后,響應(yīng)體為ResponseBody類型,我們需要將ResponseBody解析后才能得到我們想要的數(shù)據(jù),那么如果我們想要直接在響應(yīng)的時候拿到我們想要的數(shù)據(jù)怎么辦呢?這時候我們就需要Converter來幫我們進行轉(zhuǎn)換了。Retrofit提供了幾個轉(zhuǎn)換器,如下表:

依賴庫 Gradle引用 來源
Gson com.squareup.retrofit2:converter-gson 官方
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 Framework com.squareup.retrofit2:converter-simpleframework 官方
Scalars com.squareup.retrofit2:converter-scalars 官方
LoganSquare com.github.aurae.retrofit2:converter-logansquare 第三方
FastJson org.ligboy.retrofit2:converter-fastjson 或org.ligboy.retrofit2:converter-fastjson-android 第三方

我們用Gson來介紹一下如何使用,首先引入Gson的Converter:

 com.squareup.retrofit2:converter-gson:2.1.0

然后通過Retrofit.Builder()配置添加Converter:

Retrofit retrofit=new Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .baseUrl("http://192.168.1.79:8080/")
        .build();

RetrofitApi retrofitApi=retrofit.create(RetrofitApi.class);

接著讓我們來測試一下吧:

接口返回數(shù)據(jù)格式為:

{
    "status": "1",
    "message": "success",
    "data": {
        "name": "zyyoona7",
        "age": "18",
        "height": "180cm"
    }
}

兩個實體類分別為BaseResult和User:

//BaseResult類
public class BaseResult<T> {

    public static final int FAILURE = 0; // 失敗
    public static final int SUCCESS = 1; // 成功

    private int status;  // 返回狀態(tài):0 失敗   1 成功
    private String message;  // 返回信息
    private T data;  // 包裝的對象
    //...省略getter setter
}

//User類
public class User implements Parcelable {

    private String name;
    private int age;
    private String height;
  
    //省略getter setter
}

請求接口:

@GET("public")
Call<BaseResult<User>> getUser();

代碼調(diào)用:

RetrofitApi retrofitApi=retrofit.create(RetrofitApi.class);

Call<BaseResult<User>> userCall=retrofitApi.getUser();
userCall.enqueue(new Callback<BaseResult<User>>() {
            @Override
            public void onResponse(Call<BaseResult<User>> call, Response<BaseResult<User>> response) {
                //直接解析出我們想要的數(shù)據(jù)
            }

            @Override
            public void onFailure(Call<BaseResult<User>> call, Throwable t) {

            }
        });

2.為Retrofit添加RxJava支持

支持RxJava簡直就是Retrofit的大招哇,用起來超級酷,如果你對RxJava還不了解請移步RxJava學(xué)習(xí)資料鏈接,是時候用起RxJava了。我們來配置一下,使Retrofit支持RxJava:

首先導(dǎo)入:

compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.1.6'

然后通過Retrofit.Builder配置:

Retrofit retrofit=new Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
       //RxJava支持
      .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
      .baseUrl("http://192.168.1.79:8080/")
        .build();

RetrofitApi retrofitApi=retrofit.create(RetrofitApi.class);

接著接口的返回值需要轉(zhuǎn)變一下:

@GET("public")
Observable<BaseResult<User>> getUser();

這時候就可以開車了:

retrofitApi.getUser()
        .flatMap(new Func1<BaseResult<User>, Observable<User>>() {
            @Override
            public Observable<User> call(BaseResult<User> userBaseResult) {
                return Observable.just(userBaseResult.getData());
            }
        })
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Subscriber<User>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(User user) {
                Log.e(TAG, "onNext: " + user);
            }
        });

3.為Retrofit添加日志攔截器

Retrofit是很強大,但是調(diào)試的時候想要看到請求和響應(yīng)的信息怎么辦呢?Retrofit是一個封裝,它依賴了OkHttp作為客戶端,從源碼中可以看出:

 public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
   //...省略
 }

從方法中看出,如果callFactory為null則會創(chuàng)建新的OkHttpClient,而且在Builder中提供了client()方法,可以讓我們重新設(shè)置Client。這樣我們可以通過給OkHttpClient添加攔截器來實現(xiàn)打印日志。

官方給我們提供了一個攔截器:

compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'

在Retrofit2.1.0的版本中,如果我們的項目不導(dǎo)入OkHttp,默認將會導(dǎo)入OkHttp-3.3.0和okio-1.8.0,我們可以導(dǎo)入最新的OkHttp:

compile 'com.squareup.okhttp3:okhttp:3.4.1'

創(chuàng)建HttpLoggingInterceptor對象:

HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

打印日志有四個級別:

  • Level.BODY:打印請求頭,請求體和響應(yīng)頭,響應(yīng)體的所有內(nèi)容
  • Level.HEADERS:打印請求和響應(yīng)的頭部信息
  • Level.BASIC:打印基本信息
  • Level.NONE:無打印

配置到Retrofit中:

Retrofit retrofit=new Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        //配置OkHttpClient
        .client(new OkHttpClient().newBuilder().addInterceptor(loggingInterceptor).build())
        .baseUrl("http://192.168.1.79:8080/")
        .build();

RetrofitApi retrofitApi=retrofit.create(RetrofitApi.class);

這樣我們就可以暢爽的看日志信息了~~~

4.為Retrofit添加請求頭

在項目中或多或少都會用到請求頭,比如登錄的token之類的,具體看服務(wù)器端如何規(guī)定,上面再介紹注解的時候我們已經(jīng)看到了可以通過@Headers或者@Header來添加頭部信息(具體寫法請看Retrofit的注解第3小節(jié))。這兩種寫法只是給特定的接口添加,如果接口多的話那手指就得抽筋了,有沒有統(tǒng)一添加頭部的方法呢?答案是肯定的。依然通過給OkHttp添加攔截器的方式。

自定義HeaderInterceptor:

public class HeaderInterceptor implements Interceptor {

    private Map<String, String> headers = new HashMap<>();

    public HeaderInterceptor(Map<String, String> headers) {
        this.headers = headers;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {

        Request.Builder builder = chain.request().newBuilder();
        for (String key : headers.keySet()) {
            builder.addHeader(key, headers.get(key));
        }
        Request request = builder.build();
        return chain.proceed(request);
    }

然后就可以愉快的使用了:

Map<String,String> headerMap=new HashMap<>();
headerMap.put("token","123456");
//...more
HeaderInterceptor headerInterceptor=new HeaderInterceptor();

Retrofit retrofit=new Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        //配置OkHttpClient
        .client(new OkHttpClient().newBuilder()
                .addInterceptor(loggingInterceptor)
                .addInterceptor(headerInterceptor)
                .build())
        .baseUrl("http://192.168.1.79:8080/")
        .build();

RetrofitApi retrofitApi=retrofit.create(RetrofitApi.class);

更多使用可以猛戳:https://github.com/square/retrofit/wiki/Retrofit-Tutorials

Demo努力趕制中...其他篇幅努力編寫中...

參考

如何使用Retrofit請求非Restful API
你真的會用Retrofit2嗎?Retrofit2完全教程
Retrofit官網(wǎng)
Retrofit Wiki

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,363評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,497評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,305評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,727評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,193評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,411評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,945評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,777評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,978評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,216評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,657評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,960評論 2 373

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,782評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,643評論 25 708
  • 整體Retrofit內(nèi)容如下: 1、Retrofit解析1之前哨站——理解RESTful2、Retrofit解析2...
    隔壁老李頭閱讀 4,004評論 8 19
  • 音級 樂音體系中的各個音,如1234567 就是各個音級。 全音和半音 把一個八度的距離等分為12等份,每一份就是...
    debugman007閱讀 1,827評論 0 2
  • 十來年沒有看過電視,對電影卻一直非常喜歡。喜歡電影,第一是節(jié)省時間,看兩部電視劇或一個綜藝節(jié)目的時間,就足以去看一...
    劉建強閱讀 222評論 0 0