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 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 call = request.getCall(1, 10);
  public void callRequest() {
    //发送网络请求(异步)
    call.enqueue(new Callback() {
      @Override
      public void onResponse(Call call, Response response) {
        //对返回数据进行处理
        response.body().name;
      }
      @Override
      public void onFailure(Call 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
}

源码分析的七个要点:

  • 通过动态代理生成网络请求对象
  • 解析网络请求接口的注解,生成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 observable = request.getCall();
    //通过线程切换发送网络请求
    observable.subscribeOn(Schedulers.io())     //切换到IO线程进行网络请求
            .observeOn(Schedulers.newThread())  //切换回到主线程处理请求结果
            .subscribe(new Observer() {
              @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只能返回Observable且转换函数更灵活)、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 s) {
        final SubscribeOnObserver parent = new SubscribeOnObserver(s);

        s.onSubscribe(parent);

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

    final class SubscribeTask implements Runnable {
        private final SubscribeOnObserver parent;

        SubscribeTask(SubscribeOnObserver 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 { 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)

 

你可能感兴趣的:(开源框架)