RxJava学习笔记

RxJava学习笔记

什么是RxJava—实现异步操作的库

一个在Java VM上使用可观测的序列来组成异步的、基于事件的程序的库

优点

简洁,随着程序逻辑变得越来越复杂,它依然能够保持简洁

原理简析

RxJava的异步实现是通过一种扩展的观察者模式来实现的

观察者模式:观察者通过注册(订阅)的方式告诉被观察者,你必须在某个状态发生变化时通知我(eg:安卓中的点击监听)

RxJava的观察者模式

  • Observable(被观察者)
  • Observer(观察者)
  • subscribe(订阅)
  • 事件

RxJava的事件回调除了普通事件onNext()(相当于onClick()/onEvent())之外,还定义了两个特殊的事件:onCompleted()和onError()

  • onCompleted():事件队列完结,RxJava不仅把每个事件单独处理,还会把它们看做一个队列(当不会再有新的onNext()发出时,需要触发onCompleted()方法作为标志)
  • onError():事件队列异常,在事件处理过程中出现异常时触发,同时队列自动终止

基本实现

  • 1)创建Observer(观察者,决定事件触发时做什么操作)

    Observer<String> observer = new Observer<String>() {
        @Override
        public void onNext(String s) {
            Log.d(tag, "Item: " + s);
        }
    
        @Override
        public void onCompleted() {
            Log.d(tag, "Completed!");
        }
    
        @Override
        public void onError(Throwable e) {
            Log.d(tag, "Error!");
        }
    };
    

    除了Observer接口之外,RxJava还内置了一个实现了Observer的抽象类:Subscriber。Subscriber对Observer接口进行了一些扩展,但是基本实现方式是一样的

    Subscriber<String> subscriber = new Subscriber<String>() {
        @Override
        public void onNext(String s) {
            Log.d(tag, "Item: " + s);
        }
    
        @Override
        public void onCompleted() {
            Log.d(tag, "Completed!");
        }
    
        @Override
        public void onError(Throwable e) {
            Log.d(tag, "Error!");
        }
    };
    

    Observer和Subscriber的区别

    • 1.onStart():这是Subscriber增加的方法,会在事件未发送之前被调用,可以用于做一些准备工作(eg:数据清空),默认实现为空

    • 2.unsubscribe():这是Subscriber实现Subscription接口的方法,用于取消订阅。isUnsubscribed()用了判断状态,unsubscribe()方法一般放在onPause/onStop()方法中来解除引用关系,避免内存泄露

  • 2)创建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被订阅的时候,OnSubscribe的call()方法会自动被调用,事件序列会依照设定依次触发,实现了由被观察者调用观察者的回调方法,完成由被观察者向观察者的事件传递

    快捷创建事件队列的方法:

    //just(T...): 将传入的参数依次发送出来
    Observable observable = Observable.just("Hello", "Hi", "Aloha");
    
    //from(T[]) / from(Iterable<? extends T>) : 将传入的数组或 Iterable 拆分成具体对象后,依次发送出来
    String[] words = {"Hello", "Hi", "Aloha"};
    Observable observable = Observable.from(words);
    
  • 3)Subscribe(订阅,创建了Observable和Observer之后,再用subscribe()方法将它们联结起来)

    observable.subscribe(observer);
    // 或者:
    observable.subscribe(subscriber);
    

    内部实现(核心代码):

    public Subscription subscribe(Subscriber subscriber) {
        subscriber.onStart();
        onSubscribe.call(subscriber);
        return subscriber;
    }
    

示例:

由指定的一个 drawable 文件 id drawableRes 取得图片,并显示在 ImageView 中,并在出现异常的时候打印 Toast 报错

int drawableRes = ...;
ImageView imageView = ...;
Observable.create(new OnSubscribe<Drawable>() {
    @Override
    public void call(Subscriber<? super Drawable> subscriber) {
        Drawable drawable = getTheme().getDrawable(drawableRes));
        subscriber.onNext(drawable);
        subscriber.onCompleted();
    }
}).subscribe(new Observer<Drawable>() {
    @Override
    public void onNext(Drawable drawable) {
        imageView.setImageDrawable(drawable);
    }

    @Override
    public void onCompleted() {
    }

    @Override
    public void onError(Throwable e) {
        Toast.makeText(activity, "Error!", Toast.LENGTH_SHORT).show();
    }
});

创建被观察者——>被观察者中决定触发什么样的事件及触发的顺序——>订阅观察者(new Observer)——>在观察者中执行具体的操作

线程控制——Scheduler

默认情况下,RxJava遵循线程不变的原则,哪个线程调用subscribe()就在哪个线程生产和消费事件,如需切换线程,就要用到Scheduler(调度器)

  • Scheduler的API

    • Schedulers.immediate():直接在当前线程运行,默认的Scheduler
    • Schedulers.newThread():总是启用新线程,并在新线程中执行操作
    • Schedulers.io():I/O操作(读写文件、读写数据库、网络信息交互等)所使用的Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。
    • Schedulers.computation():计算所使用的Scheduler。这个 Scheduler 使用固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
    • Android中还有一个专用的AndroidSchedulers.mainThread(),它指定的操作将在Android主线程运行

示例:

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.d(tag, "number:" + number);
            }
        });

变换

RxJava提供了对事件序列进行变换的支持,这是它的核心功能之一。所谓变换,就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列

示例:map()

Observable.just("images/logo.png") // 输入类型 String
    .map(new Func1<String, Bitmap>() {
        @Override
        public Bitmap call(String filePath) { // 参数类型 String
            return getBitmapFromPath(filePath); // 返回类型 Bitmap
        }
    })
    .subscribe(new Action1<Bitmap>() {
        @Override
        public void call(Bitmap bitmap) { // 参数类型 Bitmap
            showBitmap(bitmap);
        }
    });

Func1类:和Action1非常相似,也是RxJava的一个接口,用于包装含有一个参数的方法。Func1和Action1的区别在于,Func1包装的是有返回值的方法。

示例中,map()方法将参数中的String对象转换成一个Bitmap对象后返回

示例: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);

示例中是通过传入一组Student对象,打印出每个Student选择的Course,这里用map()显然是不行的,因为map()是一对一的转化。

这个时候就要用到flatMap()了,flatMap()也是把传入的参数转化后返回另一个对象,但和map()不同的是flatMap()返回的是个Observable对象,并且这个Observable对象并不是被直接发送到了Subscriber的回调方法中。而是利用这个Observable发送事件,这些事件会被汇入同一个Observable,而这个Observable负责将这些事件统一交给Subscriber的回调方法。

flatMap()还常用于嵌套的异步操作,如Retorfit+RxJava

networkClient.token() // 返回 Observable<String>,在订阅时请求 token,并在响应后发送 token
.flatMap(new Func1<String, Observable<Messages>>() {
    @Override
    public Observable<Messages> call(String token) {
        // 返回 Observable<Messages>,在订阅时请求消息列表,并在响应后发送请求到的消息列表
        return networkClient.messages();
    }
})
.subscribe(new Action1<Messages>() {
    @Override
    public void call(Messages messages) {
        // 处理显示消息列表
        showMessages(messages);
    }
});

线程的自由控制

利用subscribeOn()结合observeOn()可以实现线程的控制,让事件的产生和消费发生在不同的线程。其中subscribeOn()的线程控制可以从事件发出的开端就造成影响,而observeOn()控制的是它后面的线程,示例:

Observable.just(1, 2, 3, 4) // IO 线程,由 subscribeOn() 指定
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.newThread())
    .map(mapOperator) // 新线程,由 observeOn() 指定
    .observeOn(Schedulers.io())
    .map(mapOperator2) // IO 线程,由 observeOn() 指定
    .observeOn(AndroidSchedulers.mainThread) 
    .subscribe(subscriber);  // Android 主线程,由 observeOn() 指定

如上,通过observeOn()的多次调用,程序实现了线程的多次切换,不同于observeOn(),subscribeOn()的位置放在哪里都可以,但是只能调用一次

延伸:doOnSubscribe()

Subscriber的onStart()可以用作流程开始前的初始化,但是不能指定线程,而Observable.doOnSubscribe()同样是在subscribe()调用后而且在事件发送前执行,但区别在于它可以指定线程。默认情况下, doOnSubscribe() 执行在 subscribe() 发生的线程;而如果在 doOnSubscribe() 之后有 subscribeOn() 的话,它将执行在离它最近的 subscribeOn() 所指定的线程。

Observable.create(onSubscribe)
    .subscribeOn(Schedulers.io())
    .doOnSubscribe(new Action0() {
        @Override
        public void call() {
            progressBar.setVisibility(View.VISIBLE); // 需要在主线程执行
        }
    })
    .subscribeOn(AndroidSchedulers.mainThread()) // 指定主线程
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(subscriber);

参考:
http://gank.io/post/560e15be2dca930e00da1083

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值