rxjava的探索,rxjava2

rxjava2

如果生产者的速度大于消费者的速度,就会产生Backpressure问题。即异步情况下,Backpressure问题才会存在。

由于上游通过Observable发射数据的速度大于下游通过Consumer接收处理数据的速度,而且上下游分别运行在不同的线程中,下游对数据的接收处理不会堵塞上游对数据的发射,造成上游数据积压,内存不断增加,最后便会导致内存溢出。

Observable.create(new ObservableOnSubscribe<Integer>() { // 第一步:初始化Observable
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
                Log.e(TAG, "Observable emit 1" + "\n");
                e.onNext(1);
                Log.e(TAG, "Observable emit 2" + "\n");
                e.onNext(2);
                Log.e(TAG, "Observable emit 3" + "\n");
                e.onNext(3);
                e.onComplete();
                Log.e(TAG, "Observable emit 4" + "\n" );
                e.onNext(4);
            }
        }).subscribe(new Observer<Integer>() { // 第三步:订阅

            // 第二步:初始化Observer
            private int i;
            private Disposable mDisposable;

            @Override
            public void onSubscribe(@NonNull Disposable d) {      
                mDisposable = d;
            }

            @Override
            public void onNext(@NonNull Integer integer) {
                i++;
                if (i == 2) {
                    // 在RxJava 2.x 中,新增的Disposable可以做到切断的操作,让Observer观察者不再接收上游事件
                    mDisposable.dispose();
                }
            }

            @Override
            public void onError(@NonNull Throwable e) {
                Log.e(TAG, "onError : value : " + e.getMessage() + "\n" );
            }

            @Override
            public void onComplete() {
                Log.e(TAG, "onComplete" + "\n" );
            }
        });
  • Schedulers.io() 代表io操作的线程, 通常用于网络,读写文件等io密集型的操作;
  • Schedulers.computation() 代表CPU计算密集型的操作, 例如需要大量计算的操作;
  • Schedulers.newThread() 代表一个常规的新线程;
  • AndroidSchedulers.mainThread() 代表Android的主线程

1、非背压

 /**
 * 非背压
 * Observable对应Observer
 */
private void createObservable() {
    //被观察者
    Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(ObservableEmitter<String> e) throws Exception {
            e.onNext("This");
            e.onNext("is");
            e.onNext("RxJava");
            e.onComplete();
        }
    });
    //观察者
    Observer<String> observer = new Observer<String>() {
        Disposable disposable;

        @Override
        public void onSubscribe(Disposable d) {
            disposable = d;
        }

        @Override
        public void onNext(String s) {
            Log.i(TAG, "onNext: " + s);
        }

        @Override
        public void onError(Throwable e) {
            Log.i(TAG, "onError: " + e.getLocalizedMessage());
        }

        @Override
        public void onComplete() {
            Log.i(TAG, "onComplete");
            //取消订阅
            if (!disposable.isDisposed()) {
                disposable.dispose();
            }
        }
    };
    observable.subscribe(observer);
}

2、背压

/**
 * 背压(在异步过程中,由于被观察者发射数据过快,而观察者处理数据不及时,
 * 导致内存里堆积了太多数据,从而OOM,可以选择不同的策略处理该问题)
 * Flowable对应subscriber
 */
private void createFlowable() {
    Flowable<String> flowable = Flowable.create(new FlowableOnSubscribe<String>() {
        @Override
        public void subscribe(FlowableEmitter<String> e) throws Exception {
            if (!e.isCancelled()) {
                e.onNext("This");
                e.onNext("is");
                e.onNext("RxJava");
                e.onComplete();
            }
        }
        //抛弃策略
    }, BackpressureStrategy.DROP);

    Subscriber<String> subscriber = new Subscriber<String>() {
        Subscription subscription;
        @Override
        public void onSubscribe(Subscription s) {
            subscription = s;
            //请求一个数据
            subscription.request(1);
        }

        @Override
        public void onNext(String s) {
            Log.i(TAG, "onNext: " + s);
            //处理完后,再请求一个数据
            subscription.request(1);
        }

        @Override
        public void onError(Throwable e) {
            Log.i(TAG, "onError: " + e.getLocalizedMessage());
        }

        @Override
        public void onComplete() {
            Log.i(TAG, "onComplete");
            //取消订阅
            subscription.cancel();
        }
    };
    flowable.subscribe(subscriber);
}



关于有无返回值,有返回值便于管理

subscribe(Observer);无返回值  

subscribe(Consumer);有返回值 

subscribeWith(new ResourceObserver)有返回值 

 

 

 

OnClickListener 观察者模式

如图所示,通过 setOnClickListener() 方法,Button 持有 OnClickListener 的引用(这一过程没有在图上画出);当用户点击时,Button 自动调用 OnClickListener 的 onClick() 方法。另外,如果把这张图中的概念抽象出来(Button -> 被观察者、OnClickListener -> 观察者、setOnClickListener() -> 订阅,onClick() -> 事件),就由专用的观察者模式(例如只用于监听控件点击)转变成了通用的观察者模式。如下图:

通用观察者模式

而 RxJava 作为一个工具库,使用的就是通用形式的观察者模式。

RxJava 的观察者模式

RxJava 有四个基本概念:Observable (被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer

 

 

rxjava原理:观察者模式+handler机制切换线程

 

rxjava线程切换

  1. 只有第一subscribeOn() 起作用(所以多个 subscribeOn() 没意义),

    doOnSubscribe受下面的subscribeOn控制线程
  2. 这个 subscribeOn() 控制从流程开始的第一个操作,直到遇到第一个 observeOn()

  3. observeOn() 可以使用多次,每个 observeOn() 将导致一次线程切换(),这次切换开始于这次 observeOn() 的下一个操作

  4. 不论是 subscribeOn() 还是 observeOn(),每次线程切换如果不受到下一个 observeOn() 的干预,线程将不再改变,不会自动切换到其他线程

 

 

 

just,from是做集合遍历的,

flatMap是做类型转换的,并且是一对多的类型转换,

map也是类型转换的是一对一的转换,

 

flatMap和map的区别 map String,String -> String

                                         flatMap    String,Observable<String>  ->    String

 

/*           -------------------------------map-------------------------------------------------*/

Observable.just("a", "b", "c")
        //使用map进行转换,参数1:转换前的类型,参数2:转换后的类型
        .map(new Func1<String, String>() {
            @Override
            public String call(String i) {
                String name = i;
                Log.i("map", "map--1----" + i);
                return name;
            }
        })
        .subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                Log.i("map", "map--2----" + s);
            }
        });

11-23 10:24:31.350 12902-12902/com.example.seele.retrofit I/tag: map--1----a

11-23 10:24:31.350 12902-12902/com.example.seele.retrofit I/tag: map--2----a

11-23 10:24:31.350 12902-12902/com.example.seele.retrofit I/tag: map--1----b

11-23 10:24:31.350 12902-12902/com.example.seele.retrofit I/tag: map--2----b

11-23 10:24:31.350 12902-12902/com.example.seele.retrofit I/tag: map--1----c

11-23 10:24:31.350 12902-12902/com.example.seele.retrofit I/tag: map--2----c

/* -------------------------------flatMap-------------------------------------------------*/

   Observable.just("a", "b", "c").flatMap(new Func1<String, Observable<String>>() {
            @Override
            public Observable<String> call(String s) {
                Log.i("flatMap", "map--1----" + s);
                return Observable.just(s + "!!!", "d");
            }
        }).subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<String>() {
                    @Override
                    public void call(String s) {
                        Log.i("flatMap", "map--2----" + s);
                    }
                });
 

11-23 10:53:51.320 14442-14527/? I/tag: map--1----a

11-23 10:53:51.320 14442-14527/? I/tag: map--1----b

11-23 10:53:51.320 14442-14527/? I/tag: map--1----c

11-23 10:53:51.340 14442-14442/? I/tag: map--2----a!!!

11-23 10:53:51.340 14442-14442/? I/tag: map--2----b!!!

11-23 10:53:51.340 14442-14442/? I/tag: map--2----c!!!

map是分个返回,flatMap是集中返回

 

 

filter是做筛选的过滤的,

   Observable.just(3, 4, 5, 6).filter(new Func1<Integer, Boolean>() {
            @Override
            public Boolean call(Integer integer) {
                return integer > 4;
            }
        }).subscribe(item -> Log.d("JG", item.toString())); //5,6

 

concat: 按顺序连接多个Observables。需要注意的是Observable.concat(a,b)等价于a.concatWith(b)。串行

 Observable<Integer> observable1 = Observable.just(1, 2, 3, 4);
        Observable<Integer> observable2 = Observable.just(4, 5, 6);
        Observable.concat(observable1, observable2).subscribe(item -> Log.d("JG", item.toString()));//1,2,3,4,4,5,6

 

 

 

startWith: 在数据序列的开头增加一项数据。startWith的内部也是调用了concat



 
  Observable.just(1, 2, 3, 4, 5)
                .startWith(6, 7, 8)
                .subscribe(item -> Log.d("JG", item.toString()));//6,7,8,1,2,3,4,5

merge和concat对照,是并行的

 

interval返回一个每隔指定的时间间隔就发射一个序列号的 Observable 对象,可用来做倒计时等操作。

例子: 每隔 1 s 发送一个序列号,序列号从 0 开始,每次累加 1

Observable<Long> observable = Observable.interval(1, TimeUnit.SECONDS);

 

take只发射前面指定数量或指定时间内的元素。Observable.just(-1, -2,0,1,2).take(3); // 只发射前三条数据


 Observable.just(3,4,5,6)
            .take(3)//发射前三个数据项
            .take(100, TimeUnit.MILLISECONDS)//发射100ms内的数据

 

默认情况下, doOnSubscribe() 是和被观察者在一个线程(订阅者线程),并且是第一个执行的,可以执行比如:网络访问的加载框,多个doOnSubscribe从下向上顺序执行, 在doOnSubscribe紧跟后面使用subscribeOn() 控制执行的线程

compose

好处在于:  1.实现一系列操作符的复用    2.不破坏链式调用的结构

compose和flatmap的区别

我们知道,compose和flatMap都是以Observable<T>作为输入,Observable<R>作为输出,那么两者有什么区别呢

1.compose() 是唯一一个能从流中获取原生Observable 的方法,因此,影响整个流的操作符(像subscribeOn()和observeOn())需要使用compose(),相对的,如果你在flatMap()中使用subscribeOn()/observeOn(),它只影响你创建的flatMap()中的Observable,而不是整个流。
2.当你创建一个Observable流并且内联了一堆操作符以后,compose()会立即执行,flatMap()则是在onNext()被调用以后才会执行,换句话说,flatMap()转换的是每个项目,而compose()转换的是整个流。
3.flatMap()一定是低效率的,因为他每次调用onNext()之后都需要创建一个新的Observable,compose()是操作在整个流上的。
 

rxjava操作符大全https://www.jianshu.com/p/3fdd9ddb534b

 

 

  1. 倒计时的实现
  2.  
  3.  final int count = 30;  
  4.   
  5.                 Observable.interval(01, TimeUnit.SECONDS)//设置0延迟,每隔一秒发送一条数据  
  6.                         .take(count+1//设置循环11次  
  7.                         .map(new Func1<Long, Long>() {  
  8.                             @Override  
  9.                             public Long call(Long aLong) {  
  10.                                 return count-aLong; //  
  11.                             }  
  12.                         })  
  13.                         .doOnSubscribe(new Action0() {  
  14.                             @Override  
  15.                             public void call() {  
  16.                                 mSend.setEnabled(false);//在发送数据的时候设置为不能点击  
  17.   
  18.                                 mSend.setBackgroundColor(Color.GRAY);//背景色设为灰色  
  19.                             }  
  20.                         })  
  21.   
  22.                         .observeOn(AndroidSchedulers.mainThread())//操作UI主要在UI线程  
  23.                         .subscribe(new Observer<Long>() {  
  24.                             @Override  
  25.                             public void onCompleted() {  
  26.                                 Log.d(TAG, "onCompleted: ");  
  27.                                 mSend.setText("获取验证码");//数据发送完后设置为原来的文字  
  28.                                 mSend.setTextColor(Color.BLACK);  
  29.                                 mSend.setBackgroundColor(Color.parseColor("#f97e7e"));//数据发送完后设置为原来背景色  
  30.                             }  
  31.   
  32.                             @Override  
  33.                             public void onError(Throwable e) {  
  34.                                 e.printStackTrace();  
  35.                             }  
  36.   
  37.                             @Override  
  38.                             public void onNext(Long aLong) { //接受到一条就是会操作一次UI  
  39.                                 Log.d(TAG, "onNext: "+aLong);  
  40.                                 mSend.setText("剩余时间"+aLong+"秒");  
  41.                                 mSend.setEnabled(true);  
  42.                                 mSend.setTextColor(Color.WHITE);  
  43.   
  44.                             }  
  45.                         });  

 

 

异步的实现

 

Observable.create(new Observable.OnSubscribe<String>() {

    @Override

    public void call(Subscriber<? super String> subscriber) {

      //可以做各种复杂的操作,然后进行回调
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        subscriber.onNext("jack : 我是最后的执行结果");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        subscriber.onNext("jack : 我被计算出来了");

        subscriber.onCompleted();

    }

}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
        .subscribe( //此行为订阅,只有真正的被订阅,整个流程才算生效

        new Observer<String>() {

            @Override

            public void onCompleted() {

                Log.d(TAG, "onCompleted");

            }

            @Override

            public void onError(Throwable e) {

                Log.d(TAG, e.toString());

            }

            @Override

            public void onNext(String s) {

                Log.d(TAG, s);

            }

        });

 

 

线程
倘若我们要进行一些数据的耗时操作,而且线程切换自由
在RxJava 中,Scheduler ——调度器,相当于线程控制器,

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

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 主线程运行。

 

 new Thread() {
            @Override
            public void run() {
                super.run();
                for (File folder : folders) {
                    File[] files = folder.listFiles();
                    for (File file : files) {
                        if (file.getName().endsWith(".png")) {
                            final Bitmap bitmap = getBitmapFromFile(file);
                            getActivity().runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    imageCollectorView.addImage(bitmap);
                                }
                            });
                        }
                    }
                }
            }
        }.start();

 

而如果使用 RxJava ,实现方式是这样的:

 

      Observable.from(folders)
                .flatMap(new Func1<File, Observable<File>>() {
                    @Override
                    public Observable<File> call(File file) {
                        return Observable.from(file.listFiles());
                    }
                })
                .filter(new Func1<File, Boolean>() {
                    @Override
                    public Boolean call(File file) {
                        return file.getName().endsWith(".png");
                    }
                })
                .map(new Func1<File, Bitmap>() {
                    @Override
                    public Bitmap call(File file) {
                        return getBitmapFromFile(file);
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Bitmap>() {
                    @Override
                    public void call(Bitmap bitmap) {
                        imageCollectorView.addImage(bitmap);
                    }
                });

代码块可以看出操作符是有先后顺序的,

 

just,from是做集合遍历的,

flatMap是做类型转换的,

并且是一对多的类型转换,

map也是类型转换的是一对一的转换,

filter是做筛选的过滤的,

interval返回一个每隔指定的时间间隔就发射一个序列号的 Observable 对象,可用来做倒计时等操作。

例子: 每隔 1 s 发送一个序列号,序列号从 0 开始,每次累加 1

Observable<Long> observable = Observable.interval(1, TimeUnit.SECONDS);

take只发射前面指定数量或指定时间内的元素。Observable.just(-1, -2,0,1,2).take(3); // 只发射前三条数据

 

默认情况下, doOnSubscribe() 是和被观察者在一个线程(订阅者线程),并且是第一个执行的,可以执行比如:网络访问的加载框,多个doOnSubscribe从下向上顺序执行, 在doOnSubscribe紧跟后面使用subscribeOn() 控制执行的线程

 

下载

 

   Observable.just(url)
                .filter(new Predicate<String>() { // 过滤 call的map中已经有了,就证明正在下载,则这次不下载
                    @Override
                    public boolean test(String s) {
                        return !downCalls.containsKey(s);
                    }
                })
                .map(new Function<String, DownloadInfo>() { // 生成 DownloadInfo
                    @Override
                    public DownloadInfo apply(String s) {
                        return createDownInfo(s);
                    }
                })
                .map(new Function<Object, DownloadInfo>() { // 如果已经下载,重新命名
                    @Override
                    public DownloadInfo apply(Object o) {
                        return getRealFileName((DownloadInfo)o);
                    }
                })
                .flatMap(new Function<DownloadInfo, ObservableSource<DownloadInfo>>() { // 下载
                    @Override
                    public ObservableSource<DownloadInfo> apply(DownloadInfo downloadInfo) {
                        return Observable.create(new DownloadSubscribe(downloadInfo));
                    }
                })
                .observeOn(AndroidSchedulers.mainThread()) // 在主线程中回调
                .subscribeOn(Schedulers.io()) //  在子线程中执行
                .subscribe(new DownloadObserver()); //  添加观察者,监听下载进度

/**
 * Created by lhy
 * Date:2018年 09月 12日
 * Time:13:50
 * —————————————————————————————————————
 * About: 观察者
 * —————————————————————————————————————
 */
public class DownloadObserver implements Observer<DownloadInfo> {

    public Disposable d;//可以用于取消注册的监听者
    public DownloadInfo downloadInfo;

    @Override
    public void onSubscribe(Disposable d) {
        this.d = d;
    }

    @Override
    public void onNext(DownloadInfo value) {
        this.downloadInfo = value;
        downloadInfo.setDownloadStatus(DownloadInfo.DOWNLOAD);
        EventBus.getDefault().post(downloadInfo);
    }

    @Override
    public void onError(Throwable e) {
        Log.d("My_Log","onError");
        if (DownloadManager.getInstance().getDownloadUrl(downloadInfo.getUrl())){
            DownloadManager.getInstance().pauseDownload(downloadInfo.getUrl());
            downloadInfo.setDownloadStatus(DownloadInfo.DOWNLOAD_ERROR);
            EventBus.getDefault().post(downloadInfo);
        }else{
            downloadInfo.setDownloadStatus(DownloadInfo.DOWNLOAD_PAUSE);
            EventBus.getDefault().post(downloadInfo);
        }

    }

    @Override
    public void onComplete() {
        Log.d("My_Log","onComplete");
        if (downloadInfo != null){
            downloadInfo.setDownloadStatus(DownloadInfo.DOWNLOAD_OVER);
            EventBus.getDefault().post(downloadInfo);
        }
    }
}

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值