小白學習 Retrofit2 由淺入深

原文鏈接:
http://www.jianshu.com/p/a8b88c7fe831
http://blog.csdn.net/qq_24889075/article/details/52181133

概述

在學習 Retrofit2 的過程中受到了一些阻力,現 Retrofit2 學會使用了,特此寫此文驗證所學知識。同時也希望幫助和我一樣在學習Retrofit2遇到困難的猿們。

當我在剛開始學習 Retrofit2 的時候並不知道Retrofit2是什麼東西,後來逐漸瞭解 “它可能是一個方便我們網絡請求的庫 ,可以幫我們讓請求網絡變得更靈活、易於維護”。然後還可以和時下比較火熱的RxJava進行完美融合。

先看看如何使用,如何進行一個簡單的Get/Post請求

Retrofit2 入門

首先在build.gradle中添加如下代碼,添加Retrofit2庫

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

有的教程裏寫要手動添加okhttp的庫,其實是不需要的,因爲retrofit2封裝了okhttp,不信自己編譯下看看:
gradle

External libraries

添加完庫,我們開始正文。

我們在項目中進行網絡請求時,肯定不是一個地址吧,那麼這些請求地址存放在哪呢?是在哪個類裏請求就在哪個類裏存放,還是統一放在一個專門存地址的類中呢?
我在學習Android期間就是哪裏有請求就放哪裏,後來有人告訴我要集中存放。於是後來就建立一個AppURL.java所有地址都存放這裏。
然而Retrofit2這裏也可以這麼理解:專門有一個‘地方’來存儲鏈接地址(也可以創建多個‘地方’存儲)。這個‘地方’不是類而是接口,在這個接口中可以設定請求地址的一些信息。就像這樣:

public interface AppURL { 
    @GET("index") 
    Call<ResponseBody> getIndex();
    ...
    ...
//  可以存儲多個連接地址
}

說明:
接口名“AppURL ”可以隨意定義,根據自己喜好。
第一行:代表get請求,請求地址爲“設定的BaseURL/index” (BaseURL設定在下面介紹如何設定)
第二行:getIndex是方法名;Call是默認返回類型,暫且不要管能幹什麼。

下面我們看下如何使用這些地址進行網絡請求:
1. 創建Retrofit對象,並設定BaseURL

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://www.這裏是BaseURL.com/")
                .build();

需要注意的是BaseURL必須以‘/’結尾

  1. 獲取“AppURL”對象(創建請求服務)
AppURL url= retrofit.create(AppURL.class);
  1. 用AppURL對象得到具體請求對象(獲取請求服務方法 )
Call<ResponseBody> call = getIndex.getIndex();

後期也會在這一步中進行設置鏈接參數、請求頭等

  1. 開始(異步)請求
call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                Log.e("tag", response.body().toString());//獲得數據
            }
            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.e("tag", t.getMessage());//請求失敗
            }
        });

好了,現在一個簡單的網絡請求就寫完了。不是很難吧(當時我可是覺得挺難 ^_^)

單單會這些是遠遠不夠的,那麼我們如何來滿足項目中各種各樣的需求呢?請繼續看

Retrofit2 進階

自動解析

其實在Retrofit2中,我們不用自己來解析數據,Retrofit2可以幫我們自動解析,怎麼做呢?請看:
0. 添加
在Retrofit2中是用Gson解析的,所以我們要在build.gradle中添加。

compile 'com.squareup.retrofit2:converter-gson:2.1.0'

有寫教程說還有添加gosn庫,經過測試是不需要的,converter-gson中已經封裝了gson庫。
需要注意的是converter-gson和retrofit版本號應爲一致,在這裏我都用2.1.0
1. 創建Bean
創建一個JavaBean,用於解析服務器返回數據。就和我們平常自己解析創建的Bean一樣,推薦用As的插件JsonFormat,挺方便的。
我們創建一個Bean起名爲MBean.java(隨便起的)
2. 爲retrofit添加addConverterFactory
添加後的代碼如下:

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://www.這裏是BaseURL.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
  1. 修改泛型
//在AppURL 接口中修改:
@GET("index")
    Call<MBean> getIndex();
 Call<MBean> call = url.getIndex();
//調用服務請求時的修改
        call.enqueue(new Callback<MBean>() {
            @Override
            public void onResponse(Call<MBean> call, Response<MBean> response) {
                Log.e("tag", response.body().toString());//解析好的數據
            }

            @Override
            public void onFailure(Call<MBean> call, Throwable t) {
                Log.e("tag", t.getMessage());
            }
        });

這樣輸出的就直接是用Gson解析好的MBean數據了。

retrofit不僅僅只支持gson,還支持其他許多json解析庫。 如:
Jackson、Moshi、Protobuf、Wire、Simple XML、Scalars (primitives, boxed, and String) 具體請看官網

固定地址/路徑替換

說到固定地址了,那麼固定地址長什麼樣呢?

http://www.BaseURL.com/index
http://www.BaseURL.com/user
http://www.BaseURL.com/login
http://www.BaseURL.com/register/qq
http://www.BaseURL.com/register/wechat

那麼應該如何請求呢?除了上面例子中的寫法還可以這樣寫:

    @請求類型("{name}" Call<返回類型> 方法名(@path("name") String name);
如:

  @GET("{name}")
    Call<MBean> get(@Path("name") String urlName);

//如果想訪問登錄的鏈接,在使用時就直接url.get("login");就可以。這樣請求的地址就是http://www.BaseURL.com/login 是不是很方便
//注意@Path和{}中的參數名要一致

@Path的應該作用暫且理解爲 爲上面的GET請求傳值

帶參地址

帶參地址長這樣子:

www.BaseURL.com/login?page=1
www.BaseURL.com/movieTop?start=1&count=5
www.BaseURL.com/login?username=testuser&password=123456

上個用的是@Path,這回用的是@Query其實和@Path一樣
直接看例子:

@GET("movieTop")
    Call<MBean> get(@Query("start") int start, @Query("count") int count);
//假設想查詢電影排行榜的第1-5名,則使用時候是這樣:
Call<MBean> call = url.get(1, 5);
//請求的地址是這樣:www.BaseURL.com/movieTop?start=1&count=5

Post帶Body請求

使用@Body來聲明即可,如下:

 @POST("/aaa")
 Call<MBean> send( @Body UserInfo body);
//使用
Call<MBean> call=url.send();

這裏的UserInfo就是要發送的實體,Retrofit2 會自動轉成Gson  

學到這裏,一般的網絡請求都可以了進行,可以應付一陣子了。
還有一些要求較高的請求,請看下節。

Retrofit2 大成

如果看到這裏,相信對Retrofit2的基本請求會用了,那麼這節就說一說其他的網絡請求。

表單(FormUrlEncoded)

我們可以使用@FormUrlEncoded註解來發送表單數據。使用 @Field註解和參數來指定每個表單項的Key,value爲參數的值。

@FormUrlEncoded
@POST("user/login")
Call<User> updateUser(@Field("username") String name, @Field("password") String pass);

單文件上傳(Multipart)

 @Multipart
    @POST("register")
    Call<User> registerUser(
      @Part MultipartBody.Part headPhoto, 
      @Part("username") RequestBody userName, 
      @Part("password") RequestBody passWord
  );
//使用
MediaType textType = MediaType.parse("text/plain");
RequestBody name = RequestBody.create(textType, "二傻子");
RequestBody pass = RequestBody.create(textType, "123456");

RequestBody photoRequestBody = RequestBody.create(MediaType.parse("image/png"), 文件對象);
MultipartBody.Part photo = MultipartBody.Part.createFormData("上傳的key", "文件名.png", photoRequestBody);

Call<User> call = url.registerUser(photo,name, pass);

@Part 後面支持三種類型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意類型;

動手測試:username的RequestBody 換成String是否可以

多文件上傳

@Multipart
@POST("register")
Call<User> registerUser(@PartMap Map<String, RequestBody> params,  @Part("password") RequestBody password);
//使用
RequestBody photo = RequestBody.create(MediaType.parse("image/png"), 文件對象2);
RequestBody photo = RequestBody.create(MediaType.parse("image/png"), 文件對象2);
Map<String,RequestBody> photos = new HashMap<>();
photos.put("對應的key1"; filename=\"文件名1.png", photo1);
photos.put("對應的key2"; filename=\"文件名2.png", photo2);
photos.put("username",  RequestBody.create(null, "二傻子"));

Call<User> call = userBiz.registerUser(photos, RequestBody.create(null, "123456"));

也可以都塞Map裏上傳,也可以只在Map中上傳文件,隨你嘍~
文章結尾有參考鏈接。不一樣的上傳方式。

請求頭

  1. 固定請求頭
     @GET("地址")
     @Headers("Accept-Encoding: application/json")
     Call<返回類型> 方法名();
    // 請求結果:
    // GET 地址 HTTP/1.1
    // Accept-Encoding: application/json
  1. 動態請求頭
     @GET("地址")
     Call<返回類型> 方法名(@Header("Location") String location);
    //使用
    url.方法名("參數");
    // 請求結果:
    // GET 地址 HTTP/1.1
    // Location: 參數
  1. 固定+動態
     @GET("地址")
     @Headers("Accept-Encoding: application/json")
     Call<返回類型> 方法名(@Header("Location") String location);
    //使用
    url.方法名("參數");
    // 請求結果:
    // GET 地址 HTTP/1.1
    // Accept-Encoding: application/json
    // Location: 參數

其他

  1. 注意XXXMap的使用, 比如@PathMap,@FieldMap等,具體怎麼使用,可以自己研究,研究不出來的可以參考結尾處的文章。

  2. 下載文件得說說,在Retrofit2中下載文件是默認存儲到緩存中,也就是說不能進行大的文件下載,如果要下載大文件要用 @streaming 。但話說回來了,下載文件我們可以不用Retrofit2啊,直接用okhttp不就得啦

  3. 我們是可以添加 okhttpclient 到retrofit中去,這樣可以來統一的log管理,給每個請求添加統一的header等,那麼我們沒有添加爲什麼沒有報錯呢? 因爲在build()方法中會判斷是否爲空,如果我們沒有添加okhttpclient 則就是空了,那麼retrofit會自動給我們添加了一個new OkHttpClient();

  4. execute是同步執行 需要在子線程中執行、enqueue是異步執行。
  5. 看下我這幾個圖,整理一下思路吧

HTTP請求方法

以上表格中的除HTTP以外都對應了HTTP標準中的請求方法,而HTTP註解則可以代替以上方法中的任意一個註解,有3個屬性:method、path、hasBody, 這裏是用HTTP註解實現的例子

public interface BlogService {
    /**
     * method 表示請的方法,不區分大小寫
     * path表示路徑
     * hasBody表示是否有請求體
     */
    @HTTP(method = "get", path = "blog/{id}", hasBody = false)
    Call<ResponseBody> getFirstBlog(@Path("id") int id);
}

標記類

參數類

注1:{佔位符}和PATH儘量只用在URL的path部分,url中的參數使用Query和QueryMap 代替,保證接口定義的簡潔
注2:Query、Field和Part這三者都支持數組和實現了Iterable接口的類型,如List,Set等,方便向後臺傳遞數組。

    Call<ResponseBody> foo(@Query("ids[]") List<Integer> ids);
    //結果:ids[]=0&ids[]=1&ids[]=2

Retrofit2 獨斷萬古

首先說下如何和當前火熱的RxJava進行配合使用。

  1. 引入RxJava支持 (版本號要一致)
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
  1. 寫接口
@GET(" ^_^ ")
    Observable<MBean> get();
  1. 通過RxJavaCallAdapterFactory爲Retrofit添加RxJava支持
Retrofit retrofit = new Retrofit.Builder()
      .baseUrl("http://www.BaseURL.com/")
      .addConverterFactory(GsonConverterFactory.create())//自動通過Gson轉josn,上面有提到
      .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//添加RxJava支持
      .build();
  1. 使用
url.get()
        .subscribeOn(Schedulers.io())
        .subscribe(new Subscriber<MBean>() {
            @Override
            public void onCompleted() {
            }
            @Override
            public void onError(Throwable e) {
            }
            @Override
            public void onNext(MBean mBean) {
            }
        });

根據需要添加RxAndroid,這個版本號沒有要求。

剩下的內容講的主要是進行自定義 Converter自定義CallAdapter。還有就是源碼的解析
這裏可以參考結尾處的鏈接,不獻醜了。


參考地址

這些是我在學習過程中收集的一些資料,個人感覺還不錯。
本文部分內容來自於下面部分文章

鴻洋:http://blog.csdn.net/lmj623565791/article/details/51304204#t1
圖片來源(經過作者授權拿的圖):http://www.jianshu.com/p/308f3c54abdd

其他博客:
http://blog.csdn.net/ljd2038/article/details/51046512
http://blog.csdn.net/biezhihua/article/details/49232289
多文件上傳參考:
http://www.chenkaihua.com/2016/04/02/retrofit2-upload-multipart-files.html
http://www.jianshu.com/p/acfefb0a204f

https://futurestud.io/blog/retrofit-getting-started-and-android-client

小說看多了,起的名有些怪。。。 見諒啊 ^_^

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章