Retrofit 2.0 學(xué)習(xí)第二彈——使用篇

前言

Retrofit是當(dāng)下比較熱門的一個(gè)網(wǎng)絡(luò)框架豫领,相信很多公司都在使用赞枕,即使你沒使用過這個(gè)框架窒舟,也應(yīng)該聽過
MVP+Retrofit+Rxjava 或者 Retrofit+Rxjava+Okhttp+MVP 這樣的組合怎憋。本篇只是一篇對Retrofit的入門介紹及簡單使用姨丈,后面再逐步框架上過渡,慢慢來埃难!

1 簡介

Retrofit 官方地址

Retrofit源碼地址.PNG

如果沒有一些基礎(chǔ)莹弊,像我一樣涤久,直接看官方文檔,估計(jì)也會(huì)看的一頭霧水箱硕,因?yàn)槲臋n很簡潔拴竹,上來就直接給出使用的方法。

需要的一些基礎(chǔ)知識還得自己去補(bǔ)剧罩,上一篇關(guān)于 Retrofit 中涉及到的一些基礎(chǔ),主要是 Http 和 RESTful Api座泳,需要補(bǔ)的童鞋可以看看
Retrofit2.0學(xué)習(xí)第一彈——準(zhǔn)備篇

Retrofit 是 Android 之神 JakeWharton 寫的網(wǎng)絡(luò)框架惠昔,github 地址

Retrofit-JakeWharton.PNG

Retrofit 是基于 OkHttp 進(jìn)行的封裝挑势,遵循 RESTful Api,通過注解來設(shè)計(jì)請求接口镇防,Retrofit 實(shí)際上是對網(wǎng)絡(luò)請求參數(shù)通過注解方式設(shè)置,包括 Header潮饱、URL等来氧,
然后請求操作通過 okhttp 來完成,從服務(wù)器返回的請求結(jié)果香拉,okhttp 又交給 Retrofit 根據(jù)需要進(jìn)行解析(通過 Converter)啦扬,
對于開發(fā)者來說,更加簡潔和方便凫碌。OkHttp 也是 square 公司開發(fā)的網(wǎng)絡(luò)框架扑毡,JakeWharton 也是主要開發(fā)者之一。

Retrofit-okhttp.PNG

2 特點(diǎn)

對于 Retrofit 的描述盛险,官方給出了這樣一句話:

A type-safe HTTP client for Android and Java

意思是說 Retrofit 是方便 Android 和 Java 使用的一種 Http 安全客戶端請求框架瞄摊。

下面給出一張圖,說明 Retrofit 的主要特點(diǎn)苦掘。

Retrofit特點(diǎn).png

另外换帜,既然 Retrofit 是依賴 Okhttp,那么到底他們之間的關(guān)系是怎樣的呢鹤啡?惯驼,再來一張圖。

Retrofit與OkHttp.png

理清了關(guān)系揉忘,我們該干什么呢跳座?首先肯定是先動(dòng)手實(shí)踐一下,看看 Retrofit 如何使用泣矛,是否真的很好用疲眷,然后要想深入研究的話,可以去看源碼啦您朽。

3 使用

步驟一:添加依賴庫

1. 在 build.gradle 中添加依賴庫狂丝,由于 Retrofit 依賴 OkHttp换淆,所以還需要添加 okhttp 的依賴,版本號可以在官網(wǎng)上的 Github 中獲取几颜。
dependencies {
  //引入okhttp
  compile 'com.squareup.okhttp3:okhttp:3.5.0'
  //引入retrofit
  compile 'com.squareup.retrofit2:retrofit:2.1.0'
  //引入rxjava
  //compile 'io.reactivex.rxjava2:rxjava:2.0.4'
  //引入Log攔截器倍试,方便DEBUG模式輸出log信息
  //compile 'com.squareup.okhttp3:logging-interceptor:3.5.0'
  //引入json轉(zhuǎn)換器,方便將返回的數(shù)據(jù)轉(zhuǎn)換為json格式
  compile 'com.squareup.retrofit2:converter-gson:2.1.0'
}

步驟二:建立數(shù)據(jù)實(shí)體類

這里使用的是郭神《第一行代碼》天氣例子中的城市請求的 URL蛋哭。


public class City {

    int id;
    String name;

    public String toString() {

        return "[id = " + id + ", name = " + name + "]";
    }
}

步驟三:設(shè)計(jì)請求接口

Retrofit 請求通過 java 接口創(chuàng)建县习,這句話描述的不太清楚,實(shí)際上我們使用時(shí)谆趾,只要將 請求方法放在接口中躁愿,通過注解方式對請求參數(shù)進(jìn)行描述和配置,調(diào)用方法的實(shí)例是框架通過動(dòng)態(tài)代理完成的沪蓬,在源碼中能夠找到彤钟。

有以下兩點(diǎn)需要注意:

  • 設(shè)計(jì)的接口不能繼承嵌套,嵌套意思是在一個(gè)接口中不能再有一個(gè)接口跷叉,這一點(diǎn)也是實(shí)驗(yàn)過程中發(fā)現(xiàn)逸雹,想了下,如果熟悉注解的話云挟,應(yīng)該能夠理解梆砸,注解也是不能繼承和嵌套。

  • 接口中的所有方法都需要進(jìn)行注解植锉,注解相應(yīng)的網(wǎng)絡(luò)請求操作辫樱。

public interface GetService {

    @GET("api/china")
    Call<List<Province>> getProvinces();
}

上面是最簡單的一個(gè)網(wǎng)絡(luò)請求接口,下面對注解的各種類型進(jìn)行說明俊庇。

Retrofit注解類型.png
1 請求方法注解

方法注解常用的有這幾個(gè):@GET狮暑、@POST、@PUT辉饱、@PATCH 搬男、@DELETE、@HEAD 彭沼、@OPTIONS缔逛、@HTTP
注解對應(yīng)著 Http 中的方法,這在上一篇文章的講解中已有了詳細(xì)的說明姓惑,是對應(yīng)著請求的具體的動(dòng)作褐奴。其中,GET于毙、POST最常用敦冬,HTTP也可能用到,反正我沒用到唯沮,那就對這三個(gè)進(jìn)行說明脖旱,其他的遇到了再補(bǔ)充堪遂。

@GET

上面例子中就是 @GET 的請求,注解 @GET 的方法萌庆,向服務(wù)器請求指定 URL 地址的資源溶褪,數(shù)據(jù)流方向:服務(wù)器--->客戶端,使用時(shí)一般會(huì)配合 @Path践险,通過 @Path 注解方法參數(shù)猿妈,使得請求的 URL 能夠動(dòng)態(tài)改變,更加靈活捏境,后面會(huì)對 @Path 詳細(xì)講解于游。

@POST

注解成 @POST 方法,表明向服務(wù)器發(fā)送數(shù)據(jù)垫言,所以數(shù)據(jù)流方向很明確,客戶端--->服務(wù)器
@POST 注解的方法向服務(wù)器發(fā)送數(shù)據(jù)倾剿,主要 Form 表單類型筷频,一般配合 FormUrlEncoded 或者 MultiPart 注解。

@HTTP

@HTTP 是概括性的注解方法前痘,具體的參數(shù)是在后面括號中進(jìn)行說明凛捏,這里只給出請求方法的配置,還有其他參數(shù)可以設(shè)置芹缔,如 path,hasBody 等

/**
 * method:網(wǎng)絡(luò)請求的方法坯癣,對應(yīng) HTTP 的請求方法
 */
@HTTP(method = "GET",path = "api/china")
Call<ResponseBody> getCall();

//等同于
@GET("api/china")
Call<List<Province>> getProvinces();

2 方法標(biāo)記類注解

方法注解類參數(shù)主要是對方法進(jìn)行一個(gè)標(biāo)記最欠,不同于方法請求示罗,主要對數(shù)據(jù)類型進(jìn)行說明。

@FormUrlEncoded

用于 POST 請求方法芝硬,注解后蚜点,表明發(fā)送 Form 表單數(shù)據(jù),與 @Field 或 @FieldMap 配合使用拌阴。

public interface PostService {

    @POST("path")
    @FormUrlEncoded
    Call<Translation> getTranslate(@Field("key") String value);

    //或者使用FieldMap绍绘,根據(jù)需要來選擇

    @POST("path")
    @FormUrlEncoded
    Call<Translation> getTranslate(@FieldMap Map<String,String> maps);
}
@MultiPart

使用 @MultiPart 標(biāo)記的方法中可以傳遞三種類型的數(shù)據(jù):

(1)RequestBody,參數(shù)中需要使用 @Part 標(biāo)記字段

(2)MultipartBody.Part 類型,@Part 標(biāo)記迟赃,但不需要注明字段陪拘,一般用于文件

(3)其他類型,如 String 類型或者其他自定義類型

直接來上代碼:

public interface UpLoadService {

  //1 upload a image
  @Multipart
  @POST("user")
  Call<ResponseBody> upload(@Part("file\";filename=\"image.jpg") RequestBody file);

  //2 upload some images,the number is certain
  @Multipart
  @POST("user")
  Call<ResponseBody> upload(@Part("file\";filename=\"image1.jpg") RequestBody file1,@Part("file\";filename=\"image2.jpg") RequestBody file2,@Part("file\";filename=\"image3.jpg") RequestBody file3);

  //3 upload one image and text
  @Multipart
  @POST("user")
  Call<ResponseBody> upload(@Part("description") String description,
                            @Part MultipartBody.Part file);

  //4 upload one image and text
  @Multipart
  @POST("user")
  Call<ResponseBody> upload(@Part("description") RequestBody description,@Part MultipartBody.Part file);

  /**********************************************************************/

  //5 upload images and text
  @Multipart
  @POST("user")
  Call<ResponseBody> upload(@Part("description") RequestBody description,
                           @PartMap() Map<String,RequestBody> maps);
}

下面一個(gè)一個(gè)分析:
1 和 2 是用來上傳圖片的纤壁,只不過 2 是用來上傳多張圖片左刽。可能一上來有些迷糊摄乒,這就是上一篇文章中提到的關(guān)于請求的消息結(jié)構(gòu)部分組成悠反,這里再拿出來說明一下残黑。

POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA

//第一部分,文本
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"
title

//第二部分斋否,圖片
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="image1.jpg" //注意這里的 name 和 filename
Content-Type: image/png
PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

需要上傳 RequestBody梨水,而 @Part 部分注明就是圖片的 Content-Disposition:
看注釋部分的 name 和 filename,就是 @Part("file";filename="image1.jpg") 給出的茵臭。這里沒有實(shí)際驗(yàn)證疫诽,因?yàn)槲覜]有自己搭建后臺部分,所示這里只是說明旦委。

3 和 4 方法是一樣的奇徒,實(shí)現(xiàn)文字和圖片同時(shí)上傳,MultipartBody.Part 部分的 @Part 不需要給出相應(yīng)的字段缨硝。另外摩钙,為啥給出 3 和 4 這兩種方式,看起來 3 更加簡單查辩,但是有篇文章 Retrofit上傳單圖胖笛、多圖、圖文 說上傳圖文時(shí)遇到了坑宜岛,使用 String 類型的話长踊,服務(wù)端接收到的參數(shù)會(huì)帶雙引號。這里仍需要實(shí)際驗(yàn)證萍倡,我沒有做驗(yàn)證身弊,為了保險(xiǎn)起見,使用 RequestBody 類型肯定沒有問題列敲。

5 實(shí)現(xiàn)的是多張圖片和文字的上傳阱佛,使用 @PartMap() 進(jìn)行標(biāo)記,其中 Map< String,RequestBody > 也可換成 List< MultipartBody.Part>酿炸,同樣能夠?qū)崿F(xiàn)多張圖片上傳瘫絮。

使用過程

private void upload() {

        UpLoadService upLoadService = getService("http://webset", UpLoadService.class);

        File file1 = new File("d:/1/test1.jpg");
        File file2 = new File("d:/1/test2.jpg");
        File file3 = new File("d:/1/test3.jpg");

        //upload serveral images, the number is certain
        RequestBody requestFile1 = RequestBody.create(MediaType.parse("multipart/form-data"), file1);
        RequestBody requestFile2 = RequestBody.create(MediaType.parse("multipart/form-data"), file2);
        RequestBody requestFile3 = RequestBody.create(MediaType.parse("multipart/form-data"), file3);

        Map<String, RequestBody> maps = new HashMap<>();

        //the key is the field in the database
        maps.put("image1", requestFile1);
        maps.put("image2", requestFile2);
        maps.put("image3", requestFile3);

        String describString = "this are images and text";
        RequestBody description = RequestBody.create(MediaType.parse("multipart/form-data"), describString);

        Call<ResponseBody> uploadImagesAndTextCall = upLoadService.upload(description, maps);

        //execute the call
        uploadImagesAndTextCall.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                Log.e("tag", "upload the images and text success");
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.e("tag", "upload the image and text failed");
            }
        });
    }
Content-Type

Content-Type即內(nèi)容類型,上面使用的都是 multipart/form-data填硕,代表二進(jìn)制數(shù)據(jù)類型麦萤,對于圖片也可以使用 image/jpg 格式,對于 Json 類型可以使用 application/json 類型

City city = new City(1, "Beijing");
String jsonString = new Gson().toJson(city);

RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8")
        , jsonString);
小結(jié)

@MultiPart 很不好理解扁眯,反正我是看了很久壮莹,才有了一些理解,另外還需要實(shí)際操作姻檀,加深理解命满,實(shí)際使用中可能不需要這么多方式,那就根據(jù)需求選擇其中一種先用起來绣版,然后再改進(jìn)胶台。

@Streaming

嗯歼疮,沒用過,自己腦補(bǔ)去吧诈唬,哈哈韩脏!

3 方法參數(shù)注解

方法參數(shù)這部分也很多,為了方便理解和記憶铸磅,有些可以看成是相同的赡矢,像 @Field 和 @FieldMap,@Query 和 @QueryMap阅仔,@Part 和 @PartMap吹散,@Headers 和 @Header(這兩個(gè)和前面三對還有些區(qū)別)。

@Path
@GET("api/{Country}")
Call<List<Province>> getProvinces(@Path("Country") String country);

通過 Path 注解八酒,可以將 GET 中{Country}部分進(jìn)行動(dòng)態(tài)替換空民,這個(gè)很好理解。

@Url

@Url 注解同樣可設(shè)置 URL羞迷,達(dá)到上面 GET 后面設(shè)置的效果袭景。

@GET
Call<List<Province>> getProvinces(@Url String url);
@Field 和 @FieldMap

在進(jìn)行 POST 請求時(shí)提交請求的表單字段,可以理解為鍵值對闭树,與 @FormUrlEncoded 配合使用,在 @FormUrlEncoded 說明是也提到了荒澡,表單格式的請求類型為 Content-Type:application/x-www-form-urlencoded报辱,也是請求消息結(jié)構(gòu)的默認(rèn)類型。

@Query 和 @QueryMap

如单山,我要訪問下面這個(gè)URL碍现,在 ?之后是查詢參數(shù)米奸,這些參數(shù)就可以通過 @Query 來動(dòng)態(tài)設(shè)定昼接。

查詢參數(shù)分解為鍵值對:

key--------value

a-------------fy

f------------auto

t------------auto

w---------hello%20world

使用 @Query 對每一個(gè)鍵值對進(jìn)行參數(shù)設(shè)置,當(dāng)有多個(gè)鍵值對時(shí)悴晰,就可以通過 @QueryMap


public interface QueryService {

    //baseurl 為http://fy.iciba.com/
    @GET("ajax.php")
    Call<Message> getMessage(@Query("a") String param1,
    @Query("f") String param2, @Query("t") String param3,
    @Query("w") String param4);

    @GET("{message}")
    Call<Message> getMessage(@QueryMap Map<String, String> params);
}

使用


//getService 創(chuàng)建接口實(shí)例的方法慢睡,重點(diǎn)看下面的代碼
QueryService getService = (QueryService) getService("http://fy.iciba.com/", GetService.class);

/**
 * url
 * http://fy.iciba.com/ajax.php?a=fy&f=auto&t=auto&w=hello%20world
 */

//@Query
Call<Message> call = getService.getMessage("fy","auto","auto","hello%20world");

//@QueryMap
Map<String, String> paramsMap = new HashMap<>();
paramsMap.put("a", "fy");
paramsMap.put("f", "auto");
paramsMap.put("t", "auto");
paramsMap.put("w", "hello%20world");
Call<Message> call = getService.getMessage(paramsMap);

@Body

@Body 用來封裝自定義類型的數(shù)據(jù), 一般是通過實(shí)體對象進(jìn)行封裝的數(shù)據(jù)類型铡溪,如String 或者自己定義的實(shí)體類型漂辐。

實(shí)體類


class User{

    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

請求接口


public interface UserService {
    @POST("api/users")
    Call<ResponseBody> uploadUser(@Body User user);
}

調(diào)用

Call<ResponseBody> call = userService.uploadUser(new User("name",24));

需要注意的是,在服務(wù)器端需要自己進(jìn)行解析棕硫,不能直接獲取相應(yīng)字段數(shù)據(jù)髓涯。

@Part 和 @PartMap

這個(gè)不用多說了,在上面方法標(biāo)記類型里列出了使用方法哈扮,這部分可能稍微有點(diǎn)不好理解纬纪,多看一些文章蚓再,多練習(xí),著重看下消息結(jié)構(gòu)組成包各,就可以完全搞明白摘仅。

@Header 和 @Headers

這兩個(gè)注解都是作用于請求頭,區(qū)別在于 @Header 用于不固定的請求頭髓棋,@Headers 用于添加固定請求頭实檀,關(guān)于請求頭的概念,需要去了解下消息結(jié)構(gòu)的 header 部分按声。

@Headers 設(shè)置請求頭的Content-type膳犹,即設(shè)置編碼格式,固定請求頭 意思是使用這個(gè)請求接口的編碼格式都是一樣的签则。

public interface HeadersService {

    @Headers("Content-type:application/x-www-form-urlencoded;charset=UTF-8")
    @POST("api/users")
    Call<ResponseBody> uploadUser(@Field("username") String username);
}

@Header 設(shè)定動(dòng)態(tài)設(shè)置請求頭編碼格式须床,在調(diào)用方式,通過參數(shù)傳遞

public interface HeaderService {

    @POST("api/users")
    Call<ResponseInfo> uploadUser(@Header("Content-Type") String contentType,@Field("username") String username);
}

// 調(diào)用
Call<ResponseBody> call = service.uploadNewUser("application/x-www-form-urlencoded;charset=UTF-8","Ralf");

當(dāng)然渐裂,請求頭部分還有其他可以設(shè)置的豺旬,根據(jù)實(shí)際需要進(jìn)行設(shè)置。

至此柒凉,經(jīng)歷漫長的過程族阅,各種注解類型已經(jīng)講完,是不是有點(diǎn)多膝捞,不過不要緊坦刀,實(shí)際中使用用到的應(yīng)該不會(huì)太多吧,為啥不確定呢? 因?yàn)槲覜]用過啊蔬咬,也只是學(xué)習(xí)階段鲤遥,哈哈!在腦圖中也已經(jīng)標(biāo)出來重點(diǎn)了林艘。

步驟四:創(chuàng)建 Retrofit 實(shí)例

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(urlStr)
        .addConverterFactory(GsonConverterFactory.create()) // Gson 數(shù)據(jù)解析器
        //.addConverterFactory(MyConverterFactory.create()) // 自定義數(shù)據(jù)解析器
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // RxJava 適配器
        .build();

創(chuàng)建 Retrofit 實(shí)例可以設(shè)置解析器和適配器盖奈。

Adapter

Retrofit主要支持這幾種網(wǎng)絡(luò)請求適配器:guava、Java8 和 Rxjava
如果不設(shè)置適配器狐援,則使用 Android 默認(rèn)的 CallAdapter 钢坦。

Adopter gradle
guava com.squareup.retrofit2:adapter-guava:2.0.2
Java8 com.squareup.retrofit2:adapter-java8:2.0.2
RxJava compile 'io.reactivex.rxjava2:rxjava:2.0.4'
Converter

數(shù)據(jù)解析器,主要由以下幾種類型咕村,另外可以自己定義數(shù)據(jù)解析器

Converter gradle
Gson com.squareup.retrofit2:converter-gson:2.1.0
Jackson com.squareup.retrofit2:converter-jackson:2.0.2
Simple XML com.squareup.retrofit2:converter-simplexml:2.0.2
Protobuf com.squareup.retrofit2:converter-protobuf:2.0.2
Moshi com.squareup.retrofit2:converter-moshi:2.0.2
Wire com.squareup.retrofit2:converter-wire:2.0.2
Scalars com.squareup.retrofit2:converter-scalars:2.0.2
自定義數(shù)據(jù)解析器

解析出實(shí)體類场钉,如獲取城市的 JsonArray,解析出實(shí)體類懈涛,返回一個(gè) List

http://guolin.tech/api/china/12
[{
    "id": 57,
    "name": "石家莊"
}, {
    "id": 58,
    "name": "保定"
}, {
    "id": 59,
    "name": "張家口"
}, {
    "id": 60,
    "name": "唐山"
}, {
    "id": 61,
    "name": "廊坊"
}, {
    "id": 62,
    "name": "滄州"
}, {
    "id": 63,
    "name": "衡水"
}, {
    "id": 64,
    "name": "邢臺"
}, {
    "id": 65,
    "name": "邯鄲"
}, {
    "id": 66,
    "name": "秦皇島"
}]
public class MyConverterFactory extends Converter.Factory {

    public static MyConverterFactory create() {

        return new MyConverterFactory();
    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        return new MyConverter();
    }

    class MyConverter implements Converter<ResponseBody, List<City>> {

        @Override
        public List<City> convert(ResponseBody value) throws IOException {

            List<City> resultList = new ArrayList<>();
            String cityInfo = value.string();

            if (cityInfo == null || TextUtils.isEmpty(cityInfo)) {
                return resultList;
            }

            try {
                JSONArray jsonArray = new JSONArray(cityInfo);
                for (int i = 0; i < jsonArray.length(); i++) {

                    JSONObject object = jsonArray.getJSONObject(i);
                    String cityName = object.getString("name");
                    int cityId = object.getInt("id");
                    resultList.add(new City(cityId, cityName));
                }

            } catch (JSONException e) {

                e.printStackTrace();
            }

            return resultList;
        }
    }

}

以上作用完全可以使用 GsonConverterFactory逛万,這里自己解析主要是熟悉一下自定義數(shù)據(jù)解析器的流程。

步驟五:獲取 Call 實(shí)例

Call<Message> call = retrofit.create(XxService.class);

步驟六:執(zhí)行網(wǎng)絡(luò)請求 和 返回?cái)?shù)據(jù)處理

異步
call.enqueue(new Callback<Message>() {
            //請求成功回調(diào)該函數(shù)
            @Override
            public void onResponse(Call<Message> call, Response<Message> response) {

                Message message = response.body(); // 返回?cái)?shù)據(jù)部分
                message.show();
            }

            //請求失敗回調(diào)該函數(shù)
            @Override
            public void onFailure(Call<Message> call, Throwable t) {

            }
});
同步
try {
    Response<Message> response = call.execute();
} catch (IOException e) {
    e.printStackTrace();
}

小結(jié)

Retrofit 網(wǎng)絡(luò)請求按照上面 6 個(gè) 步驟就可以正常運(yùn)行了。需要注意以下幾點(diǎn):

  • 定義的接口類型要與服務(wù)店返回的類型對應(yīng)宇植,否則會(huì)解析錯(cuò)誤

  • 在 AndroidManifest 中需要設(shè)置權(quán)限

<uses-permission android:name="android.permission.INTERNET"/>
  • 異步請求中得封,不需要再單獨(dú)再開啟線程
  • 每個(gè)請求接口放在一個(gè)文件中,不能繼承

還有需要補(bǔ)充的地方指郁, 大家可以一起來討論一下忙上,避免一些不必要的坑。

后續(xù)將學(xué)習(xí)梳理一下Rxjava的結(jié)合闲坎,以及攔截器和一些封裝操作疫粥,敬請期待!

參考

代碼練習(xí)地址

Say Hello to Retrofit

這是一份很詳細(xì)的 Retrofit 2.0 使用教程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腰懂,一起剝皮案震驚了整個(gè)濱河市梗逮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绣溜,老刑警劉巖慷彤,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異怖喻,居然都是意外死亡底哗,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門锚沸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來跋选,“玉大人,你說我怎么就攤上這事哗蜈∫敖ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵恬叹,是天一觀的道長。 經(jīng)常有香客問我同眯,道長绽昼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任须蜗,我火速辦了婚禮硅确,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘明肮。我一直安慰自己菱农,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布柿估。 她就那樣靜靜地躺著循未,像睡著了一般。 火紅的嫁衣襯著肌膚如雪秫舌。 梳的紋絲不亂的頭發(fā)上的妖,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天绣檬,我揣著相機(jī)與錄音,去河邊找鬼嫂粟。 笑死娇未,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的星虹。 我是一名探鬼主播零抬,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼宽涌!你這毒婦竟也來了平夜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤护糖,失蹤者是張志新(化名)和其女友劉穎褥芒,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嫡良,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锰扶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了寝受。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坷牛。...
    茶點(diǎn)故事閱讀 40,503評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖很澄,靈堂內(nèi)的尸體忽然破棺而出京闰,到底是詐尸還是另有隱情,我是刑警寧澤甩苛,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布蹂楣,位于F島的核電站,受9級特大地震影響讯蒲,放射性物質(zhì)發(fā)生泄漏痊土。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一墨林、第九天 我趴在偏房一處隱蔽的房頂上張望赁酝。 院中可真熱鬧,春花似錦旭等、人聲如沸酌呆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽隙袁。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間藤乙,已是汗流浹背猜揪。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坛梁,地道東北人而姐。 一個(gè)月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像划咐,于是被迫代替她去往敵國和親拴念。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評論 2 359

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