Retrofit、RxJava基本原理(開發夠用了)

Retrofit是對OkHttp網絡庫的封裝,真正的網絡請求是通過OkHttp完成的

Retrofit主要用到了適配器模式

使用Retrofit五個步驟:

  • 創建網絡請求接口,設置請求類型和參數
  • 創建Retrofit實例,設置數據解析器(Gson、XML、Protobuf)和網絡適配器(RxJava、Coroutines)
  • 創建接口對象(動態代理),配置網絡請求參數
  • 調用接口方法返回Call對象或適配器封裝的對象
  • 處理適配器邏輯或直接通過Call對象發送網絡請求
  • 處理服務器返回的數據
class Person {
  String name;
  int age;
  int id;
}

public interface retrofit_interface {
  @GET("/course_api/wares/hot")
  Call<Person> getCall(@Query("pageSize") int pageSize, @Query("curPage")int curPage);
}

public class RetrofitDemo {
  Retrofit retrofit = new Retrofit.Builder()
          .baseUrl("http://www.sina.com/") //設置網絡請求基地址
          .addConverterFactory(GsonConverterFactory.create()) //設置數據解析器
          .addCallAdapterFactory(DefaultCallAdapterFactory.create()) //設置網絡適配器
          .build();
  //創建網絡請求接口對象
  retrofit_interface request = retrofit.create(retrofit_interface.class);
  //配置網絡請求參數,並獲取Call對象
  Call<Person> call = request.getCall(1, 10);
  public void callRequest() {
    //發送網絡請求(異步)
    call.enqueue(new Callback<Person>() {
      @Override
      public void onResponse(Call<Person> call, Response<Person> response) {
        //對返回數據進行處理
        response.body().name;
      }
      @Override
      public void onFailure(Call<Person> call, Throwable throwable) {
        System.out.println("連接失敗");
      }
    });
  }
}

//Post中用到的Request爲wire生成的Pb文件,並對Retrofit做了封裝
val retrofit = Retrofit.Builder()
    .setEndpoint(buildUrl())
    .client { SsRetrofitClient() }
    .addInterceptor(SsInterceptor())
    .addInterceptor(ClassroomInterceptor())
    .httpExecutor(SsHttpExecutor())
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .addCallAdapterFactory(CoroutineCallAdapterFactory.invoke())
    .addConverterFactory(WireConverterFactory.create())
    .addConverterFactory(GsonConverterFactory.create())

interface IGetNameApi {
  companion object {
    fun getNameApi(): IGetNameApi {
      return Classroom.context().retrofit.of(IGetNameApi::class.java)
    }
  }
  @POST("/tools/name/v1/user_name/")
  @Retry(2)
  fun getName(@Body request: GetNameRequest): Observable<GetNameResponse?>
}

源碼分析的七個要點:

  • 通過動態代理生成網絡請求對象
  • 解析網絡請求接口的註解,生成ServiceMethod對象
  • 對ServiceMethod對象進行網絡請求參數配置
  • 網絡請求適配器將網絡請求對象進行平臺適配
  • 最終創建並返回OkHttpCall類型的網絡請求對象
  • 網絡請求執行器發送網絡請求
  • 數據轉換器解析服務器返回的數據
  • 回調執行器切換線程
  • 主線程處理返回結果

通過RxJavaCallAdapter和Retrofit實現網絡請求

    //通過Retrofit發送網絡請求
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://fy.iciba.com/") // 設置網絡請求URL
            .addConverterFactory(GsonConverterFactory.create()) //設置使用Gson解析(記得加入依賴)
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //支持RxJava
            .build();
    //創建網絡請求接口的實例
    LoopRequest_interface request = retrofit.create(LoopRequest_interface.class);
    //採用Observable<...>形式對網絡請求進行封裝
    Observable<Person> observable = request.getCall();
    //通過線程切換髮送網絡請求
    observable.subscribeOn(Schedulers.io())     //切換到IO線程進行網絡請求
            .observeOn(Schedulers.newThread())  //切換回到主線程處理請求結果
            .subscribe(new Observer<Person>() {
              @Override
              public void onSubscribe(Disposable d) {
              }

              @Override
              public void onNext(Person result) {
                //接收服務器返回的數據
              }

              @Override
              public void onError(Throwable e) {
              }

              @Override
              public void onComplete() {

              }
            });

Retrofit(OkHttp包裝類) Interceptor經典用法:Passport Sdk會提供TTTokenInterceptor,用於自動處理request和response,用於從response中提取鑑權信息並在header中添加身份鑑權信息

RxJava(輕量級框架<1M),採用響應式編程,擴展了傳統的觀察者模式,讓異步編程變的更加簡潔。RxJava擁有豐富的操作符,通過Scheduler(調度器)可以很方便的實現線程切換(observeOn、subscribeOn)

觀察者模式:Observable、Observer、subscribe、Event

觀察者模式擴展:onNext、(onCompleted、onError)

RxAndroid是RxJava針對Android平臺的擴展庫

操作符分類:創建操作符、轉換操作符、過濾操作符、組合操作符、錯誤處理操作符

創建型操作符:Create(原始)、Just(創建單一值對象)、From(發射數組或列表型對象)、Defer(延遲創建、每次訂閱會創建新的Observable)、Empty(創建空的Observable,會調用onComplete、onError)、Never(創建空的永不停止的Observable)、Throw(創建一個空的但最終會發生錯誤的Observable)、Interval(定時發送,整數從0到無窮遞增)、Range(發送一定範圍內的值)、Repeat(指定重複發送的次數)

轉換操作符:Map(數據轉換)、FlatMap(平鋪,和Map的區別並不是可以返回Observable,Map也可以返回Observable,區別在於FlapMap會對映射後的數據集合做扁平化處理)、GroupBy(分組)、Buffer(聚集,分批次發送)、Window(和Buffer類似,也是聚集作用,只不過返回的是Observable對象,而Buffer直接返回數據集合)、Scan(掃描求和)

過濾型操作符:Debounce(數據產生後,超過指定時間間隔沒有新數據產生,則發送當前數據)、Distinct(去重)、ElementAt(取指定位置數據)、Filter(可指定過濾規則,比如發射的整數要大於0)、First(取第一個數據)、Last(取結尾數據)、IgnoreElements(忽略所有數據,只發送結束或錯誤)、Sample(每隔一段時間取樣發射)、Skip(跳過前幾項數據)、SkipLast(跳過後幾項數據)、Take(取前幾項數據)、TakeLast(取後幾項數據)

組合操作符:Zip(兩個數據源的數據項通過指定方法進行合併,其中一個結束或異常,另外一個也終止發射)、Merge(兩個數據源的數據項按照時間順序合併成一個新的數據流)、StartWith(在數據源之前插入數據)、CombineLatest(CombineLatest操作符類似於zip,但是隻有當原始Observable中的每一個都發射了一條數據時zip才發射數據,而CombineLatest則是當原始的Observable中任意一個發射了數據時就發射一條數據。當原始Observables的任何一個發射了一條數據時,CombineLatest使用一個函數結合它們最近發射的數據,然後發射這個函數的返回值)

錯誤處理操作符:onErrorReturn(遇到錯誤返回特定值)、onErrorResumeNext(遇到錯誤繼續,訂閱者無法捕獲錯誤信息)、onExceptionResumeNext(遇到錯誤繼續,訂閱者可以捕獲錯誤信息)

Schedule第二版理解(簡單看了代碼):

        Observable.just(1)
                .subscribeOn(Schedulers.io())
                .map {i ->
                    Log.e("zzzz", "mapThread ${android.os.Process.myTid()} $i")
                    i + 1
                }
                .observeOn(Schedulers.io())
                .map {i ->
                    Log.e("zzzz", "mapThread ${android.os.Process.myTid()} $i")
                    i + 1
                }
                .subscribeOn(Schedulers.io())
                .subscribe({
                    Log.e("zzzz", "observerThread ${android.os.Process.myTid()} $it")
                }, {
                    Log.e("zzzz", "observerThread ${android.os.Process.myTid()} $it")
                })

Observable.subscribeOn:生成ObservableSubscribeOn,內部subscribe調用subscribeActual,scheduler切換線程並執行SubscribeTask(執行source.subscribe(parent)),source代表上層的Observable。parent是封裝好的SubscribeOnObserver,SubscribeOnObserver是封裝了Observer,並沒有其他額外操作

Observable.observeOn:生成ObservableObserverOn,內部subscribe調用subscribeActual,scheduler直接調用source.subscribe(parent),並沒有進行線程切換。parent是封裝好的ObserveOnObserver,內部onNext、onComplete、onError方法會切換線程

Observable.map:生成ObservableMap,內部subscribe調用subscribeActual,scheduler直接調用source的相關方法,並沒有其他額外操作。parent是封裝好的MapObserver,內部onNext、onComplete、onError方法會直接執行map-function,然後也不會切換線程

總結一下:subscribe調用之後,一路向上調用observable.subscribe,如果遇到ObservableSubscribeOn,執行subscribe時會切換線程,並且一路上會封裝observer,默認什麼都不操作(map、observerOn除外)

基本原理:

    @Override
    public void subscribeActual(final Observer<? super T> s) {
        final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);

        s.onSubscribe(parent);

        parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
    }

    final class SubscribeTask implements Runnable {
        private final SubscribeOnObserver<T> parent;

        SubscribeTask(SubscribeOnObserver<T> parent) {
            this.parent = parent;
        }

        @Override
        public void run() {
            source.subscribe(parent);
        }
    }

https://www.jianshu.com/p/59c3d6bb6a6b

https://www.jianshu.com/p/4e78d447394e

observeOn作用於該操作符之後的操作符直到出現新的observeOn操作符

subscribeOn作用於該操作符之前的Observable的創建操符作以及doOnSubscribe 操作符 ,換句話說就是doOnSubscribe以及Observable的創建操作符總是被其之後最近的subscribeOn控制

        Observable.create(observableOnSubscribe)
            .subscribeOn(Schedulers.io())
            .map {
                i -> i + "哈哈"
                Log.e("zzzz", "${android.os.Process.myTid()} $i")
            }
//            .subscribeOn(Schedulers.io())
            .observeOn(Schedulers.io())
            .observeOn(Schedulers.io())
            .subscribe({
                Log.e("zzzz", "observerThread ${android.os.Process.myTid()} $it")
            }, {
                Log.e("zzzz", "observerThread ${android.os.Process.myTid()} $it")
            })

2019-09-19 14:50:32.407 17390-17390/com.example.rxjava2 E/zzzz: mainThread 17390
2019-09-19 14:50:32.481 17390-17416/com.example.rxjava2 E/zzzz: subscribeThread 17416
2019-09-19 14:50:32.481 17390-17416/com.example.rxjava2 E/zzzz: 17416 1
2019-09-19 14:50:32.481 17390-17416/com.example.rxjava2 E/zzzz: 17416 2
2019-09-19 14:50:32.482 17390-17418/com.example.rxjava2 E/zzzz: observerThread 17418 14
2019-09-19 14:50:32.482 17390-17418/com.example.rxjava2 E/zzzz: observerThread 17418 14

上面補充了一個用例,細想一下沒有那麼簡單,subscribeOn也可以控制下面(沒有observeOn的情況)

RxJava發射器類型:Observable、Flowable、Single、Completable、Maybe

val result = Maybe.create(MaybeOnSubscribe<String> { e ->
    e.onSuccess("testA")
    e.onComplete()
}).subscribe({ println("Maybe $it") },
             { println("Maybe onError") },
             { println("Maybe onComplete") }
            )

類型

描述

Observable

能夠發射0或n個數據,並以成功或錯誤事件終止(onNext、onComplete、onError)

Flowable

能夠發射0或n個數據,並以成功或錯誤事件終止;支持Backpressure,可以控制數據源發射的速度

Single

只發射單個數據或錯誤事件(onSuccess、onError)

Completable

不發射數據,只處理onComplete和onError事件(onComplete、onError)

Maybe

能夠發射0或1個數據,要麼成功,要麼失敗((onSuccess、onComplete)互斥關係、onError)

 

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