RxJava RxAndroid理论知识详解

Rx并不是一种新的语言,而是一种普通的Java模式,类似于观察者模式(Observer Pattern),可以将它看作一个普通的Java类库,因此你可以立即使用RxJava。而RxAndroid是RxJava的一个针对Android平台的扩展,主要用于 Android 开发

  1. API 介绍和原理简析
    RxJava 的异步实现,是通过一种扩展的观察者模式来实现的。
    RxJava 有四个基本概念:Observable (可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。
    Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。
    与传统观察者模式不同, RxJava 的事件回调方法除了普通事件 onNext() (相当于 onClick() / onEvent())之外,
    还定义了两个特殊的事件:onCompleted() 和 onError()。
    onCompleted(): 事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的 onNext() 发出时,需要触发 onCompleted() 方法作为标志。
    onError(): 事件队列异常。在事件处理过程中出异常时,onError() 会被触发,同时队列自动终止,不允许再有事件发出。
    在一个正确运行的事件序列中, onCompleted() 和 onError() 有且只有一个,并且是事件序列中的最后一个。需要注意的是,onCompleted() 和 onError() 二者也是互斥的,即在队列中调用了其中一个,就不应该再调用另一个。
  2. 基本实现
1) 创建观察者Observer
        Observer 即观察者,它决定事件触发的时候将有怎样的行为。 RxJava 中的 Observer 接口的实现方式:
Observer<String > observer = new Observer<String>() {
            @Override
            public void onNext(String s) {
                Log.e(tag, "Item: " + s);
            }

            @Override
            public void onCompleted() {
                Log.e(tag, "Completed!");
            }

            @Override
            public void onError(Throwable e) {
                Log.e(tag, "Error!");
            }
        };
除了 Observer 接口之外,RxJava 还内置了一个实现了 Observer 的抽象类:Subscriber。 Subscriber 对 Observer 接口进行了一些扩展,但他们的基本使用方式是完全一样的:
Subscriber<String> subscriber = new Subscriber<String>() {
            @Override
            public void onNext(String s) {
                Log.e(tag, "Item: " + s);
            }

            @Override
            public void onCompleted() {
                Log.e(tag, "Completed!");
            }

            @Override
            public void onError(Throwable e) {
                Log.e(tag, "Error!");
            }
        };
        Observer 和 Subscriber它们的区别对于使用者来说主要有两点:
    onStart(): 这是 Subscriber 增加的方法。它会在 subscribe 刚开始,而事件还未发送之前被调用,可以用于做一些准备工作,例如数据的清零或重置。这是一个可选方法,默认情况下它的实现为空。需要注意的是,如果对准备工作的线程有要求(例如弹出一个显示进度的对话框,这必须在主线程执行), onStart() 就不适用了,因为它总是在 subscribe 所发生的线程被调用,而不能指定线程。要在指定的线程来做准备工作,可以使用 doOnSubscribe() 方法,具体可以在后面的文中看到。
    unsubscribe(): 这是 Subscriber 所实现的另一个接口 Subscription 的方法,用于取消订阅。在这个方法被调用后,Subscriber 将不再接收事件。一般在这个方法调用前,可以使用 isUnsubscribed() 先判断一下状态。 unsubscribe() 这个方法很重要,因为在 subscribe() 之后, Observable 会持有 Subscriber 的引用,这个引用如果不能及时被释放,将有内存泄露的风险。所以最好保持一个原则:要在不再使用的时候尽快在合适的地方(例如 onPause() onStop() 等方法中)调用 unsubscribe() 来解除引用关系,以避免内存泄露的发生。
2) 创建 Observable
        Observable 即被观察者,它决定什么时候触发事件以及触发怎样的事件。 RxJava 使用 create() 方法来创建一个 Observable ,并为它定义事件触发规则:
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                subscriber.onNext("Hello");
                subscriber.onNext("Hi");
                subscriber.onNext("Aloha");
                subscriber.onCompleted();
            }
        });
Observable observable = Observable.just("Hello","Hi","Aloha"); 将传入的参数依次发送出来。
List<String> list = new ArrayList();
list.add( "1" ) ;
list.add( "2" ) ;
list.add( "3" ) ;
Observable observable = Observable.from(list);
from(T[]) / from(Iterable<? extends T>) : 将传入的数组或 Iterable 拆分成具体对象后,依次发送出来。
    3) Subscribe (订阅)
    创建了 Observable 和 Observer 之后,再用 subscribe() 方法将它们联结起来,整条链子就可以工作了。代码形式很简单:
    observable.subscribe(observer);
    // 或者:
    observable.subscribe(subscriber);

3 线程控制 —— Scheduler (一)
在RxJava 中,Scheduler ——调度器,相当于线程控制器,RxJava 通过它来指定每一段代码应该运行在什么样的线程。RxJava 已经内置了几个 Scheduler ,它们已经适合大多数的使用场景:
Schedulers.immediate(): 直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler。
Schedulers.newThread(): 总是启用新线程,并在新线程执行操作。
Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。
有了这几个 Scheduler ,就可以使用 subscribeOn() 和 observeOn() 两个方法来对线程进行控制了。 * subscribeOn(): 指定 subscribe() 所发生的线程,即 Observable.OnSubscribe 被激活时所处的线程。或者叫做事件产生的线程。 * observeOn(): 指定 Subscriber 所运行在的线程。或者叫做事件消费的线程。

Observable.just(1, 2, 3, 4)
    .subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
    .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
    .subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer number) {
            Log.e(tag, "number:" + number);
        }
    });

4 变换
所谓变换,就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列
map(): 事件对象的直接变换,它是 RxJava 最常用的变换。

map()使用
Observable.create(new Observable.OnSubscribe<String>() {
                    @Override
                    public void call(Subscriber<? super String> subscriber) {
                        Log.e( "rx_call" , Thread.currentThread().getName()  );

                        subscriber.onNext( "dd");
                        subscriber.onCompleted();
                    }
                })
                .observeOn(Schedulers.newThread())    //新线程
                .map(new Func1<String, String >() {
                    @Override
                    public String call(String s) {
                        Log.e( "rx_map" , Thread.currentThread().getName()  );
                        return s + "88";
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<String>() {
                    @Override
                    public void call(String s) {
                        Log.e( "rx_subscribe" , Thread.currentThread().getName());
                    }
                }) ;
flatMap(): 这是一个很有用但非常难理解的变换,flatMap() 中返回的是个 Observable 对象,并且这个 Observable 对象并不是被直接发送到了 Subscriber 的回调方法中
    flatMap() 的原理是这样的:1. 使用传入的事件对象创建一个 Observable 对象;2. 并不发送这个 Observable, 而是将它激活,于是它开始发送事件;3. 每一个创建出来的 Observable 发送的事件,都被汇入同一个 Observable ,而这个 Observable 负责将这些事件统一交给 Subscriber 的回调方法
   flatMap()使用  
   Student[] students = ...;
Subscriber<Course> subscriber = new Subscriber<Course>() {
    @Override
    public void onNext(Course course) {
        Log.d(tag, course.getName());
    }
};
Observable.from(students)
    .flatMap(new Func1<Student, Observable<Course>>() {
        @Override
        public Observable<Course> call(Student student) {
            return Observable.from(student.getCourses());
        }
    })
    .subscribe(subscriber);
    2) 变换的原理:lift()
    在 Observable 执行了 lift(Operator) 方法之后,会返回一个新的 Observable,这个新的 Observable 会像一个代理一样,负责接收原始的 Observable 发出的事件,并在处理后发送给 Subscriber。
    3) compose: 对 Observable 整体的变换
    它和 lift() 的区别在于, lift() 是针对事件项和事件序列的,而 compose() 是针对 Observable 自身进行变换
Observable.just("123")
       .compose(RxUtil.<String>applySchedulers())
       .subscribe(new Action1<String>() {
           @Override
           public void call(String s) {

               Log.e("call---subscribe ",Thread.currentThread().getName() +";内容="+s);
           }
       });

5 线程控制:Scheduler (二)

操作符(Operators):操作符就是为了解决对Observable对象的变换的问题
    1.Observable和Subscriber可以做任何事情
    Observable可以是一个数据库查询,Subscriber用来显示查询结果;Observable可以是屏幕上的点击事件,Subscriber用来响应点击事件;Observable可以是一个网络请求,Subscriber用来显示请求结果。

    2.Observable和Subscriber是独立于中间的变换过程的。
    在Observable和Subscriber中间可以增减任何数量的map。整个系统是高度可组合的,操作数据是一个很简单的过程。
    filter()输出和输入相同的元素,并且会过滤掉那些不满足检查条件的。
    take()输出最多指定数量的结果
    doOnNext()允许我们在每次输出一个元素之前做一些额外的事情,比如这里的保存标题

    subscribeOn(): 指定 subscribe() 所发生的线程,即 Observable.OnSubscribe 被激活时所处的线程。或者叫做事件产生的线程。
    observeOn(): 指定 Subscriber 所运行在的线程。或者叫做事件消费的线程。

    使用Observable.fromCallable()方法有两点好处:

    获取要发送的数据的代码只会在有Observer订阅之后执行。
    获取数据的代码可以在子线程中执行。

    zip  操作符,合并多个观察对象的数据。并且允许 Func2()函数重新发送合并后的数据

    scan累加器操作符的使用

    filter 过滤操作符的使用

    take :取前n个数据
    takeLast:取后n个数据
    first 只发送第一个数据
    last 只发送最后一个数据
    skip() 跳过前n个数据发送后面的数据
    skipLast() 跳过最后n个数据,发送前面的数据
    elementAt 、elementAtOrDefault
    elementAt() 发送数据序列中第n个数据 ,序列号从0开始
    如果该序号大于数据序列中的最大序列号,则会抛出异常,程序崩溃
    所以在用elementAt操作符的时候,要注意判断发送的数据序列号是否越界
    elementAtOrDefault( int n , Object default ) 发送数据序列中第n个数据 ,序列号从0开始。
    如果序列中没有该序列号,则发送默认值

    startWith() 插入数据

    delay操作符,延迟数据发送

    Timer  延时操作符的使用

    interval 轮询操作符,循环发送数据,数据从0开始递增

    doOnNext() 操作符,在每次 OnNext() 方法被调用前执行
    使用场景:从网络请求数据,在数据被展示前,缓存到本地

    12Buffer 操作符
    Buffer( int n )      把n个数据打成一个list包,然后再次发送。
    Buffer( int n , int skip)   把n个数据打成一个list包,然后跳过第skip个数据。

    throttleFirst 操作符
    使用场景:1、button按钮防抖操作,防连续点击   2、百度关键词联想,在一段时间内只联想一次,防止频繁请求服务器   

    distinct    过滤重复的数据

    distinctUntilChanged()  过滤连续重复的数据

    debounce() 操作符
    一段时间内没有变化,就会发送一个数据。

    doOnSubscribe() 
    使用场景: 可以在事件发出之前做一些初始化的工作,比如弹出进度条等等

    range 操作符的使用 

    defer 操作符

    just操作符是在创建Observable就进行了赋值操作,而defer是在订阅者订阅时才创建Observable,此时才进行真正的赋值操作。

    .subscribeOn(Schedulers.io())  和 .observeOn(AndroidSchedulers.mainThread()) 写的位置不一样,造成的结果也不一样。从例4中可以看出 map() 操作符默认运行在事件产生的线程之中。事件消费只是在 subscribe() 里面。
    对于 create() , just() , from()   等                 --- 事件产生   
    map() , flapMap() , scan() , filter()  等    --  事件加工

    subscribe()                                          --  事件消费

    事件产生:默认运行在当前线程,可以由 subscribeOn()  自定义线程
    事件加工:默认跟事件产生的线程保持一致, 可以由 observeOn() 自定义线程

    事件消费:默认运行在当前线程,可以有observeOn() 自定义

    如果只规定了事件产生的线程,那么事件消费线程将跟随事件产生线程。

   如果只规定了事件消费的线程,那么事件产生的线程和 当前线程保持一致

6 Retrofit的使用就是以下几步:
定义接口,参数声明,Url都通过Annotation指定
通过RestAdapter生成一个接口的实现类(动态代理)
调用接口请求数据
创建Retrofit 实例:

public static final String BASE_URL = "http://api.myservice.com";
    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build();

定义 Endpoints:interface 用下面的方式定义了每个endpoint 
    public interface MyApiEndpointInterface {
        // Request method and URL specified in the annotation
        // Callback for the parsed response is the last parameter

        @GET("/users/{username}")
        Call<User> getUser(@Path("username") String username);

        @GET("/group/{id}/users")
        Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);

        @POST("/users/new")
        Call<User> createUser(@Body User user);
    }   
Multipart forms:
    如果你要提交多参数表单数据(multi-part form data),可以使用@Multipart@Part注解:
    String username = "sarahjean";
    Call<User> call = apiService.getUser(username);
    call.enqueue(new Callback<User>() {
        @Override
        public void onResponse(Response<User> response) {
            int statusCode = response.code();
            User user = response.body();  
        }

        @Override
        public void onFailure(Throwable t) {
            // Log error here since request failed
        }
    });
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值