Retrofit實(shí)用指南

網(wǎng)上關(guān)于Retrofit(這里指的是Retrofit2包里的Retrofit)的文章已經(jīng)普天蓋地了!為什么還要寫這一篇呢?“扔物線”給了我啟發(fā)则奥!人們還是喜歡原創(chuàng)的東西考润,而不是東拼西湊的東西!有價(jià)值的東西读处!當(dāng)然糊治,現(xiàn)在稍微值錢一點(diǎn)的東西都拿到淘寶賣了!指望“賞”來兩個(gè)小錢發(fā)不了財(cái)罚舱!當(dāng)然不是不想你們“賞”錢井辜,而是非常想!因?yàn)檫@是文章價(jià)值的體現(xiàn)管闷,和對(duì)筆者的充分肯定粥脚!

我的筆鋒非常犀利,那是寫評(píng)論文章包个!現(xiàn)在寫的是技術(shù)文章刷允,會(huì)充分體現(xiàn)我務(wù)實(shí)求是的人格魅力!沒有深?yuàn)W的東西碧囊,也不會(huì)故弄玄虛树灶,踏踏實(shí)實(shí)的人,寫踏踏實(shí)實(shí)的文章糯而。

屁話一大堆了天通!急性子的人早開流了!言歸正傳熄驼!

一像寒、編寫Json數(shù)據(jù)的Repo類

我用JAVA開發(fā)了一個(gè)全功能的服務(wù)器,除了java庫(kù)谜洽,沒有用任何第三方庫(kù)萝映!今天不打算用我自己的服務(wù)器數(shù)據(jù)!就用Retrofit 官網(wǎng)提供的示例數(shù)據(jù)阐虚!

編寫程序前我喜歡看一看json數(shù)據(jù)是個(gè)什么鬼序臂?瀏覽器打開輸入https://api.github.com/users/octocat/repos,顯示了下列數(shù)據(jù)格式实束,使用Retrofit返回的數(shù)據(jù)也應(yīng)該是一樣的奥秆,所以就寫成:

Retrofit 返回的json數(shù)據(jù)格式為:

[{"id":18221276,"name":"git-consortium","full_name": "octocat/git-consortium","owner": {"login": "octocat","id": 583231,"avatar_url": "https://avatars3.githubusercontent.com/u/583231?v=4",...},...},{...}...]

是一個(gè)對(duì)象數(shù)組,建立對(duì)應(yīng)的POJO類咸灿,字段實(shí)在太多了构订!我們利用一小部分字段建一個(gè)Repo類,它里面還包含一個(gè)Owner類避矢。有人會(huì)說字段是否應(yīng)該完全對(duì)應(yīng)悼瘾,缺少了行不行囊榜?我試驗(yàn)過了,完全可行亥宿!我也發(fā)表過很多文章卸勺,還得過獎(jiǎng),每一篇文章都是自己的實(shí)踐過程的總結(jié)烫扼!

  public class Repo {
      public int id;
      public String name;
      public String full_name;
      public Owner owner;
  }

  public class Owner {
      public String login;
      public int id;
      public String avatar_url;
  }

二曙求、Retrofit沒有轉(zhuǎn)換器沒有調(diào)用適配器,還要使用RxJava

看了標(biāo)題挺吸引人的映企!是不是吹牛拔蛴?沒有真本事就會(huì)吹堰氓!

我就拿Retrofit的示例演示一下挤渐,直接貼代碼,你們拷貝粘貼到你們的開發(fā)工具中豆赏,看看是不是吹牛挣菲?

package com.ueuo.retrofit2;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.http.GET;
import retrofit2.http.Path;

public class Test3 {
    
    public interface GitHubService {
          @GET("users/{user}/repos")
          Call<ResponseBody> listRepos(@Path("user") String user);
        }
    

    public static void main(String[] args) throws IOException {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.github.com/")
                .build();
        
        GitHubService service = retrofit.create(GitHubService.class);
        Call<ResponseBody> repos = service.listRepos("octocat");
        
        ResponseBody response = repos.execute().body();
        
        Gson gson =new Gson();
        Type type = new TypeToken<List<Repo>>() {}.getType();
        List<Repo> zla = gson.fromJson(response.charStream(), type);
        
        Observable<List<Repo>> observable = Observable.just(zla);
        observable.flatMap(new Function<List<Repo>, ObservableSource<Repo>>(){

            @Override
            public ObservableSource<Repo> apply(List<Repo> paramT) throws Exception {
                return Observable.fromIterable(paramT);
            }
            
        }).subscribe(new Consumer<Repo>(){
            @Override
            public void accept(Repo repo) throws Exception {
                System.out.println(repo.name);
                System.out.println(repo.full_name);
                System.out.println(repo.owner.avatar_url);
            }           
        });
        
    }

}

我在Eclipse里運(yùn)行正常富稻,結(jié)果是:

git-consortium
octocat/git-consortium
https://avatars3.githubusercontent.com/u/583231?v=4
......

從上面示例可以看出掷邦,Retrofit純粹是脫褲子放屁多次一舉!繞了一大圈還是這個(gè)結(jié)果椭赋!不信的話我們就來看看抚岗!

三、Retrofit添加Converter和CallAdapter

Retrofit請(qǐng)求數(shù)據(jù)哪怔,以及與RxJava配合使用宣蔚,需要用到Converter和CallAdapter!這是非常關(guān)鍵的地方认境,被很多作者忽略胚委,或者不想把真象告訴你們!
要記住Converter是轉(zhuǎn)換json數(shù)據(jù)到j(luò)ava類叉信,例如Repo類亩冬,或者某個(gè)類型,例如List<Repo>硼身。
而CallAdapter是把Converter已經(jīng)轉(zhuǎn)換到的類或者類型硅急,變成RxJava的Observable對(duì)象!

我們一起來看示例:

package com.ueuo.retrofit2;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.CallAdapter;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.http.GET;
import retrofit2.http.Path;

/**
 * https://api.github.com/users/octocat/repos
 * 
 * @author xbn
 * 
 * 自定義Converter和 CallAdapter
 */
public class Test2 {
    
    public interface GitHubService {
          @GET("users/{user}/repos")
          Observable<List<Repo>> listRepos(@Path("user") String user);
        }
    
    public static class CustomConverter implements Converter<ResponseBody, List<Repo>> {

        public static final CustomConverter INSTANCE = new CustomConverter();
        
        public static CustomConverter create() {
            return INSTANCE;
        }

        @Override
        public List<Repo> convert(ResponseBody value) throws IOException {
            // ResponseBody --> List<Repo>
            Gson gson = new Gson();
            Type type = new TypeToken<List<Repo>>() {}.getType();
            return gson.fromJson(value.charStream(), type);
        }
    }
    
    public static class CustomConverterFactory extends Converter.Factory {

        public static final CustomConverterFactory INSTANCE = new CustomConverterFactory();

        public static CustomConverterFactory create() {
            return INSTANCE;
        }

        // 我們只關(guān)實(shí)現(xiàn)從 ResponseBody 到  List<Repo> 的轉(zhuǎn)換佳遂,所以其它方法可不覆蓋
        @Override
        public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
            Type rawtype = getRawType(type);            
            if(rawtype == List.class && type instanceof ParameterizedType) {
                return CustomConverter.create();
            }
            //其它類型我們不處理营袜,返回null就行
            return null;
        }
    }
    
    public static class CustomCallAdapter implements CallAdapter<List<Repo>, Observable<List<Repo>>> {

        private final Type responseType;

        //接口方法的返回類型的泛型類型 responseType
        CustomCallAdapter(Type responseType) {
            this.responseType = responseType;
        }

        @Override
        public Type responseType() {
            return responseType;
        }
        
        //Call<List<Repo>> -- Retrofit2的
        public Observable<List<Repo>> adapt(Call<List<Repo>> call) {
            
            Observable<List<Repo>> observable;
            try {
                observable = Observable.just(call.execute().body());
                return observable;
            } catch (IOException e) {
                e.printStackTrace();
            }           
            return null;
        }       
    }

    
    public static class CustomCallAdapterFactory extends CallAdapter.Factory {
        public static final CustomCallAdapterFactory INSTANCE = new CustomCallAdapterFactory();
        
        public static CustomCallAdapterFactory create() {
            return INSTANCE;
        }

        @Override
        public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
            //接口方法的返回類型
            Class<?> rawType = getRawType(returnType);           
            //返回值必須是Observable并且?guī)в蟹盒?            if (rawType == Observable.class && returnType instanceof ParameterizedType) {
                //接口方法的返回類型的泛型類型
                Type callReturnType = getParameterUpperBound(0, (ParameterizedType) returnType);
                                
                return (CallAdapter<?, ?>) new CustomCallAdapter(callReturnType);
            }
            return null;
        }       
    }

    public static void main(String[] args) throws IOException {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.github.com/")
                .addConverterFactory(CustomConverterFactory.create())
                .addCallAdapterFactory(CustomCallAdapterFactory.create())
                .build();
        
        GitHubService service = retrofit.create(GitHubService.class);
        Observable<List<Repo>> repos = service.listRepos("octocat");
        repos.flatMap(new Function<List<Repo>, ObservableSource<Repo>>(){

            @Override
            public ObservableSource<Repo> apply(List<Repo> paramT) throws Exception {
                return Observable.fromIterable(paramT);
            }
            
        }).subscribe(new Consumer<Repo>() {

            @Override
            public void accept(Repo paramT) throws Exception {
                System.out.println(paramT.full_name);
                
            }
            
        });
    

    }

}

拷貝到IDE運(yùn)行應(yīng)該輸出:

octocat/git-consortium
octocat/hello-worId
octocat/Hello-World
......

關(guān)鍵的地方是:

@Override
        public List<Repo> convert(ResponseBody value) throws IOException {
            // ResponseBody --> List<Repo>
            Gson gson = new Gson();
            Type type = new TypeToken<List<Repo>>() {}.getType();
            return gson.fromJson(value.charStream(), type);
        }

在Converter中Retrofit的請(qǐng)求數(shù)據(jù)還是原始數(shù)據(jù)!上面轉(zhuǎn)換成為L(zhǎng)ist<Repo>類型的對(duì)象丑罪。

然后數(shù)據(jù)交到CallAdapter:

public Observable<List<Repo>> adapt(Call<List<Repo>> call) {
            
            Observable<List<Repo>> observable;
            try {
                observable = Observable.just(call.execute().body());
                return observable;
            } catch (IOException e) {
                e.printStackTrace();
            }           
            return null;
        }   

可以看到adapt()方法中的參數(shù)類型是Call<List<Repo>> 荚板!這個(gè)類型是Retrofit的或者說是Retrofit2的(我們使用的是Retrofit2凤壁,類名還是Retrofit。)有人追究過源碼跪另,說是執(zhí)行實(shí)際網(wǎng)絡(luò)請(qǐng)求的是OkHttp3的Call客扎。我也看了源碼,沒有追得很深罚斗,感覺差不多有那么回事徙鱼,所以就信了別人的。在這個(gè)Call上查到的是一個(gè)Retrofit2包里的接口针姿。

四袱吆、這些是從哪里學(xué)來的?

我非常保守距淫!追求程序的精簡(jiǎn)绞绒,抵觸第三方庫(kù)!現(xiàn)在看來落后了榕暇!利用第三方庫(kù)可以快速輕松的開發(fā)軟件蓬衡,已經(jīng)是一股潮流了!我需要進(jìn)步彤枢!我的Retrofit2的第一任老師是ikidou的“你真的會(huì)用Retrofit2嗎?Retrofit2完全教程http://www.reibang.com/p/308f3c54abdd狰晚,他還提供了測(cè)試服務(wù)器RESTServer,非常感謝缴啡!同時(shí)也要感謝我的不懈努力壁晒!它的示例代碼,引入Android Studio3.0不行业栅,引入Eclipse也不行秒咐,本來打算放棄了,心想還有難倒程序員的碘裕?携取!就試著把源文件拷來拷去,搞定了帮孔!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末雷滋,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子你弦,更是在濱河造成了極大的恐慌惊豺,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件禽作,死亡現(xiàn)場(chǎng)離奇詭異尸昧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)旷偿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門烹俗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爆侣,“玉大人,你說我怎么就攤上這事幢妄⊥醚觯” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵蕉鸳,是天一觀的道長(zhǎng)乎赴。 經(jīng)常有香客問我,道長(zhǎng)潮尝,這世上最難降的妖魔是什么榕吼? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮勉失,結(jié)果婚禮上羹蚣,老公的妹妹穿的比我還像新娘。我一直安慰自己乱凿,他們只是感情好顽素,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著徒蟆,像睡著了一般胁出。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上后专,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天划鸽,我揣著相機(jī)與錄音,去河邊找鬼戚哎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛嫂用,可吹牛的內(nèi)容都是我干的型凳。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼嘱函,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼甘畅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起往弓,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤疏唾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后函似,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體槐脏,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年撇寞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了顿天。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片堂氯。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖牌废,靈堂內(nèi)的尸體忽然破棺而出咽白,到底是詐尸還是另有隱情,我是刑警寧澤鸟缕,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布晶框,位于F島的核電站,受9級(jí)特大地震影響懂从,放射性物質(zhì)發(fā)生泄漏三妈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一莫绣、第九天 我趴在偏房一處隱蔽的房頂上張望畴蒲。 院中可真熱鬧,春花似錦对室、人聲如沸模燥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蔫骂。三九已至,卻和暖如春牺汤,著一層夾襖步出監(jiān)牢的瞬間辽旋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工檐迟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留补胚,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓追迟,卻偏偏與公主長(zhǎng)得像溶其,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子敦间,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

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

  • 簡(jiǎn)介 剛接觸Retrofit的時(shí)候瓶逃,就寫了一篇簡(jiǎn)單的使用介紹:Retrofit 2.0基本使用方法,算是對(duì)Retr...
    Whyn閱讀 2,838評(píng)論 4 24
  • 本文將順著構(gòu)建請(qǐng)求對(duì)象->構(gòu)建請(qǐng)求接口->發(fā)起同步/異步請(qǐng)求的流程,分析Retrofit是如何實(shí)現(xiàn)的廓块。 開始之前厢绝,...
    zhuhf閱讀 1,610評(píng)論 0 10
  • 安卓開發(fā)領(lǐng)域中,很多重要的問題都有很好的開源解決方案带猴,例如Square公司提供網(wǎng)絡(luò)請(qǐng)求 OkHttp , Retr...
    aaron688閱讀 1,905評(píng)論 1 20
  • 2016年5月25日浓利,新浪微博【530網(wǎng)絡(luò)紅人節(jié)】官方微博賬號(hào)@超級(jí)紅人節(jié) 發(fā)布了#視頻紅人周#Day 9的數(shù)據(jù)播...
    今日排行榜閱讀 633評(píng)論 1 0
  • 每個(gè)女生心中都有一個(gè)公主夢(mèng)挤庇,她們?nèi)鰦沙伲齻儖舌粒鄄鬓D(zhuǎn)間只為那命中的王子嫡秕。 為了遇上那個(gè)王子渴语,女生早早地捯飭自己...
    Viricc閱讀 293評(píng)論 0 0