Retrofit學(xué)習(xí)(二)

之前的Retrofit學(xué)習(xí)(一)了解了一下Retrofit的最基本使用驹愚,不過目前最流行的Retrofit使用方式是Retrofit + RxJava + Gson, 如果要使用RxJava, 需要在創(chuàng)建Retrofit時配置RxJava對應(yīng)的CallAdapter:

    OkHttpclient client = new OkHttpClient.Builder().build();
    Retrofit retrofit = new Retrofit.Builder()
        .client(client)
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .baseUrl("http://localhost:4567/")
        .build();

下面就主要分析一下RxJava2CallAdapterFactory是如何工作的

RxJava2CallAdapterFactory

    public static RxJava2CallAdapterFactory create() {
        return new RxJava2CallAdapterFactory(null, false);
    }
    
    public static RxJava2CallAdapterFactory createAsync() {
        return new RxJava2CallAdapterFactory(null, true);
    }
    
    public static RxJava2CallAdapterFactory createWithScheduler(Scheduler scheduler) {
        if (scheduler == null) throw new NullPointerException("scheduler == null");
        return new RxJava2CallAdapterFactory(scheduler, false);
    }
    
    private final Scheduler scheduler;
    private final boolean isAsync;
    
    private RxJava2CallAdapterFactory(Scheduler scheduler, boolean isAsync) {
        this.scheduler = scheduler;
        this.isAsync = isAsync;
    }

RxJava2CallAdapterFactory提供了三個create系列方法辙芍,一般情況下氯檐,最常使用的是第一個沒有參數(shù)的create方法孟岛,即不指定SchedulerisAsync = false, isAsync指明是調(diào)用Call.execute還是Call.enqueue

RxJava2CallAdapterFactory.get


    public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        Class<?> rawType = getRawType(returnType);

        if (rawType == Completable.class) {
            return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false,
                    false, true);
        }

        boolean isFlowable = rawType == Flowable.class;
        boolean isSingle = rawType == Single.class;
        boolean isMaybe = rawType == Maybe.class;
        //確保返回值是Observable, Flowable, Single, Maybe
        if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) {
            return null;
        }

        boolean isResult = false;
        boolean isBody = false;
        Type responseType;
        //ParameterizedType指泛型類型针炉,如List<T>
        if (!(returnType instanceof ParameterizedType)) {
            String name = isFlowable ? "Flowable"
                    : isSingle ? "Single"
                    : isMaybe ? "Maybe" : "Observable";
            throw new IllegalStateException(...);
        }

        //獲取返回值的泛型參數(shù)
        Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
        Class<?> rawObservableType = getRawType(observableType);
        if (rawObservableType == Response.class) {
            //如果泛型參數(shù)是Response, 且Response沒有泛型參數(shù),拋出異常,Response必須是以泛型形式使用
            if (!(observableType instanceof ParameterizedType)) {
                throw new IllegalStateException(...);
            }
            //獲取Response<T>中的T
            responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
        } else if (rawObservableType == Result.class) {
            //如果泛型參數(shù)是Result, 且Result沒有泛型參數(shù)扳抽, 拋出異常篡帕,Result必須是以泛型形式使用
            if (!(observableType instanceof ParameterizedType)) {
                throw new IllegalStateException(...);
            }
            //獲取Result<T>中的T
            responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
            isResult = true;
        } else {
            responseType = observableType;
            isBody = true;
        }

        return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
                isSingle, isMaybe, false);
    }``

  1. 如果返回值類型是Completable, 直接返回一個RxJava2CallAdapter指定其中的isBody = true, isCompletable = true
  2. 確保方法的返回值Observable, Flowable, Single, Maybe, 否則返回null, 如果是null, 則根據(jù)之前的分析贸呢,如果CallAdapter.Factory.get()返回null, 在Retrofit.nextCallAdapter中會拋出異常(Retrofit默認有一個ExecutorCallAdapterFactory, 但如果方法返回值不是Call類型镰烧,其get()方法會直接返回null)
  3. 如果返回值不是泛型,拋出異常
  4. 獲取返回值中的泛型參數(shù)的類型楞陷,假設(shè)返回值類型Observable<Bean>, 這里獲取到的泛型參數(shù)類型就是Bean
  5. 如果泛型參數(shù)的類型是retrofit2.Responseretrofit2.Result怔鳖,確保ResponseResult也是以泛型的形式聲明的,即返回值類型是Observable<Response<T>>Observable<Result<T>>固蛾;Retrofit + RxJava2最常見的的用法是Observable<Bean> getName(...), 一般都會直接使用自定義的Bean類结执, 所以一般情況下度陆, isBody = true
  6. 返回RxJava2CallAdapter

RxJava2CallAdapter.adapt


    public Object adapt(Call<R> call) {
        //call是OkHttpCall, 將R轉(zhuǎn)換為Response<R>
        Observable<Response<R>> responseObservable = isAsync
                ? new CallEnqueueObservable<>(call)
                : new CallExecuteObservable<>(call);

        Observable<?> observable;
        if (isResult) {
            observable = new ResultObservable<>(responseObservable);
        } else if (isBody) {
            //將Response<T>轉(zhuǎn)換為T
            observable = new BodyObservable<>(responseObservable);
        } else {
            observable = responseObservable;
        }

        if (scheduler != null) {
            observable = observable.subscribeOn(scheduler);
        }

        if (isFlowable) {
            return observable.toFlowable(BackpressureStrategy.LATEST);
        }
        if (isSingle) {
            return observable.singleOrError();
        }
        if (isMaybe) {
            return observable.singleElement();
        }
        if (isCompletable) {
            return observable.ignoreElements();
        }
        return observable;
    }
  1. 首先生成一個Obsersavle<Response<R>>, 這里會根據(jù)isAsync是否為tru,來確定是生成CallEnqueueObservable還是CallExecuteObservable,這兩者的區(qū)別在于前者最終實際是調(diào)用OkHttpCall.enqueue方法献幔,后者實際調(diào)用了OkHttpCall.execute方法懂傀, 前者異步執(zhí)行,后者同步執(zhí)行
  2. Retrofit + RxJava2最常見的的用法是Observable<Bean> getName(...), 一般都會直接使用自定義的Bean類蜡感,
  3. 根據(jù)之前的分析可以知道蹬蚁,一般情況下,由于開發(fā)者都直接使用自己的Bean, 所以isBody = true郑兴, 會創(chuàng)建一個BodyObservable
  4. 之后會根據(jù)方法返回值是否是Flowable, Single, Maybe, Completable其中一種來做出具體的轉(zhuǎn)換

BodyObservable

final class BodyObservable<T> extends Observable<T> {
    private final Observable<Response<T>> upstream;

    BodyObservable(Observable<Response<T>> upstream) {
        this.upstream = upstream;
    }

    @Override
    protected void subscribeActual(Observer<? super T> observer) {
        //upstream是CallExecuteObservable或CallEnqueueObservable, BodyObserver是一個代理
        //作用就是把Response<T>轉(zhuǎn)換為T
        upstream.subscribe(new BodyObserver<T>(observer));
    }

    private static class BodyObserver<R> implements Observer<Response<R>> {
        private final Observer<? super R> observer;
        private boolean terminated;

        BodyObserver(Observer<? super R> observer) {
            this.observer = observer;
        }

        @Override
        public void onSubscribe(Disposable disposable) {
            observer.onSubscribe(disposable);
        }

        @Override
        public void onNext(Response<R> response) {
            if (response.isSuccessful()) {
                observer.onNext(response.body());
            } else {
                ...
            }            }
        }

        @Override
        public void onComplete() {
            if (!terminated) {
                observer.onComplete();
            }
        }

        @Override
        public void onError(Throwable throwable) {
            if (!terminated) {
                observer.onError(throwable);
            } else {
                ...
            }
        }
    }
}

這里upstreamCallExecutorObservableCallEnqueueObservable犀斋,一般情況下,這里會是CallExecutorObservable情连;在subscribeActual中可以看到叽粹,在傳入的observer外又包裝了一個BodyObserver, 傳入的observer就是開發(fā)者傳入的自定義Observer

CallExecutorObservable

final class CallExecuteObservable<T> extends Observable<Response<T>> {
    private final Call<T> originalCall;

    CallExecuteObservable(Call<T> originalCall) {
        this.originalCall = originalCall;
    }

    @Override
    protected void subscribeActual(Observer<? super Response<T>> observer) {
        //originalCall是OkHttpCall
        Call<T> call = originalCall.clone();
        observer.onSubscribe(new CallDisposable(call));

        boolean terminated = false;
        try {
            //call.execute會調(diào)用OkHttpCall.execute(), 從而得到okhttp3.Response
            //再從okhttp3.Response中得到okhttp3.ResponseBody, 然后調(diào)用    Converter.convert轉(zhuǎn)換結(jié)果,最后將接過封裝為retrofit.Response
            Response<T> response = call.execute();
            if (!call.isCanceled()) {
                //BodyObserver.onNext -> 自定義Onserver.onNext
                observer.onNext(response);
            }
            if (!call.isCanceled()) {
                terminated = true;
                observer.onComplete();
            }
        } catch (Throwable t) {
            ...
        }
    }

    private static final class CallDisposable implements Disposable {
        private final Call<?> call;

        CallDisposable(Call<?> call) {
            this.call = call;
        }

        @Override
        public void dispose() {
            call.cancel();
        }

        @Override
        public boolean isDisposed() {
            return call.isCanceled();
        }
    }
}

originalCallOkHttpCall, 可以看到在subscribeActual中會調(diào)用call.execute即調(diào)用OkHttpCall.execute來從而得到okhttp3.Response, 再從okhttp3.Response中得到okhttp3.ResponseBody, 然后調(diào)用 Converter.convert轉(zhuǎn)換結(jié)果蒙具,最后將結(jié)果封裝為retrofit.Response,

subscribeActual的參數(shù)observerBodyObserver, 而從之前的分析中可以看到BodyObserver的各方法會再調(diào)用開發(fā)人員自定義的Observer的響應(yīng)方法

這里看似比較抽象的一系列操作球榆,是為了獲得一個統(tǒng)一的結(jié)果, 一般開發(fā)人員在定義請求方法時,都會使用Observable<Bean>這種方式禁筏,即直接將Observable<T>中的T設(shè)為自定義Bean, 但不同場景下肯定會定義不同的類型Bean, Retrofit不可能預(yù)先知道開發(fā)人員會定義那些Bean, 為了得到一個統(tǒng)一的結(jié)果持钉,先將Bean轉(zhuǎn)換為Reponse<T>,這樣無論T是哪種類型,都可以得到一個統(tǒng)一的結(jié)果篱昔,之后再通過Response.body()將Response轉(zhuǎn)換為自定義Bean

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末每强,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子州刽,更是在濱河造成了極大的恐慌空执,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件穗椅,死亡現(xiàn)場離奇詭異辨绊,居然都是意外死亡,警方通過查閱死者的電腦和手機匹表,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門门坷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人袍镀,你說我怎么就攤上這事默蚌。” “怎么了苇羡?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵绸吸,是天一觀的道長。 經(jīng)常有香客問我,道長锦茁,這世上最難降的妖魔是什么攘轩? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蜻势,結(jié)果婚禮上撑刺,老公的妹妹穿的比我還像新娘。我一直安慰自己握玛,他們只是感情好够傍,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著挠铲,像睡著了一般冕屯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拂苹,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天安聘,我揣著相機與錄音,去河邊找鬼瓢棒。 笑死浴韭,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的脯宿。 我是一名探鬼主播念颈,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼连霉!你這毒婦竟也來了榴芳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤跺撼,失蹤者是張志新(化名)和其女友劉穎窟感,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體歉井,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡柿祈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了哩至。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躏嚎。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖憨募,靈堂內(nèi)的尸體忽然破棺而出紧索,到底是詐尸還是另有隱情袁辈,我是刑警寧澤菜谣,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響尾膊,放射性物質(zhì)發(fā)生泄漏媳危。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一冈敛、第九天 我趴在偏房一處隱蔽的房頂上張望待笑。 院中可真熱鬧,春花似錦抓谴、人聲如沸暮蹂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仰泻。三九已至,卻和暖如春滩届,著一層夾襖步出監(jiān)牢的瞬間集侯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工帜消, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留棠枉,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓泡挺,卻偏偏與公主長得像辈讶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子粘衬,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理荞估,服務(wù)發(fā)現(xiàn),斷路器稚新,智...
    卡卡羅2017閱讀 134,600評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,515評論 25 707
  • 概述 上一篇已經(jīng)記載了關(guān)于Retrofit使用的相關(guān)知識勘伺,這一片主要記錄下Retrofit實現(xiàn)的相關(guān)原理。簡要來說...
    seph_von閱讀 505評論 0 0
  • Retrofit學(xué)習(xí)(一)官網(wǎng)原文翻譯http://www.reibang.com/writer#/noteboo...
    冉冉升起的小太陽閱讀 343評論 0 0
  • 霧夕急匆匆的跑到紀念的藥房,翻箱倒柜的找了整整一天一夜 屯阀,把整個藥房都翻了個底朝天都沒沒能把仙芝草給找出來缅帘。 第二...
    夢多多閱讀 345評論 0 1