笔记:RxJava(一)

学习RxJava,做一下笔记
笔记:RxJava(二)

1、描述

  1. RxJava是一个基于事件流的实现异步操作的库,类似Androidhandler、AsyncTask
  2. 随着程序逻辑变得越来越复杂,它依然能够保持简洁
  3. RxJava 的异步实现,是通过一种扩展的观察者模式来实现的
  4. 观察模式可实现回调,采用订阅Subscribe的方式将被观察者Observable与观察者Observer链在一起,实现订阅关系,进行消息事件的通知

2、依赖地址


3、简单创建用法与理解

3.1、Observable.create(ObservsbleOnSubscribe)的使用

        /**
         * 一、创建  可观察者(Observable )  以及   生产事件
         *
         *
         * 1. 创建可观察者 Observable 对象,可观察的数据类型为String
         * 2.create() 是 RxJava 最基本的创造事件序列的方法,还有just(多个数据)、from(数据数组)等
         * 3.create(ObservableOnSubscribe)此处一个ObservableOnSubscribe对象参数
         * 4.当 Observable 被订阅时,OnSubscribe 的 call() 方法会自动被调用,即事件序列就会依照设定依次被触发
         *      也就是只有被订阅时,事件才会发送
         */
        Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Exception {
                /**
                 *  1.重写的subscribe(),自定义需要发送的事件
                 *  2. 通过 ObservableEmitter类对象,事件发射器,产生事件并通知观察者
                 */
                emitter.onNext("test1");
                emitter.onNext("test2");
                emitter.onNext("test3");
                emitter.onNext("test4");
                emitter.onComplete();
//=====================================>>>>>>>>>>关注①
                //emitter.onNext("test1");
                //emitter.onNext("test2");
                //emitter.onNext("test3");
                //emitter.onComplete();
                //emitter.onNext("test4");  
// =====================================>>>>>>>>>>关注②
//                emitter.onNext("test1");
//                emitter.onNext("test2");
//                emitter.onError(new Throwable("onError"));
//                emitter.onNext("test3");
//                emitter.onComplete();
//                emitter.onNext("test4");
            }
        });
        /**
         *
         * 二、创建   观察者 (Observer )以及 自定义响应事件的行为
         *
         *
         * 1. 创建观察者 (Observer )对象,观察数据对象为String
         * 2. 自动复写对应事件的方法 从而 响应对应的事件
         *
         *
         */
        Observer<String> observer=new Observer<String>() {
            // 观察者接收事件之前,默认最先调用复写 onSubscribe()这个方法
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                Log.d("TAG", "开始subscribe连接,接收上游可观察者(Observable)的事件");
            }

            /**
             *  当可观察者生产Next事件 这里的 观察者接收到时,会调用该复写这个方法 进行事件响应,可接收多个Next事件,
             *  直到接收到上游可观察者onComplete/onError事件,其中onComplete/onError事件是唯一的,两者之间是互斥的
             */
            @Override
            public void onNext(@NonNull String s) {
                Log.d("TAG", "接收到Next事件=="+s);
            }
            /**
             * 当可观察者生产Error事件并且 观察者接收到时,会调用该复写这个方法 进行响应
             * 当观察者接收到可观察者发过来的onError事件时,观察者不再接收事件了,但 可观察者可以继续发送事件
             * onError事件与onComplete事件时互斥的,两者只能有其一
             */
            @Override
            public void onError(@NonNull Throwable e) {
                Log.d("TAG", "接收到onError事件=="+e.toString());
            }
            // 当被观察者生产Complete事件& 观察者接收到时,会调用该复写方法 进行响应
            @Override
            public void onComplete() {
                Log.d("TAG", "接收到onComplete事件");
            }
        };

        /**
         *
         * 三、通过订阅(Subscribe)连接观察者和被观察者
         *
         * 就好比可观察者为上游的出水水管,观察者为下游接水水管,中间通过Subscribe连接,水就可以通了
         * 此时事件可产生,发射,接收
         */
        observable.subscribe(observer);

打印的log如下图
1525324457(1).png

关注① 当接收到了onComplete事件后,接收者Observer不再接收后面的事件,但可观察者Observable依然会发射事件

打印log结果

1525324655(1).jpg

关注② 当接收到了onError事件后,接收者Observer不再接收后面的事件,但可观察者Observable依然会发射事件

1525325319(1).jpg

3.1.1、RxJava的基于事件流的链式使用

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Exception {
                emitter.onNext("test1");
                emitter.onNext("test2");
                emitter.onNext("test3");
                emitter.onComplete();
                emitter.onError(new Throwable("onError"));
                emitter.onNext("test4");
            }
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                //====================================>>>>>>>>>>>关注③
                Log.e("TAG", "开始subscribe连接,接收上游可观察者(Observable)的事件");
            }

            @Override
            public void onNext(@NonNull String s) {
                Log.e("TAG", "接收到Next事件==" + s);
            }

            @Override
            public void onError(@NonNull Throwable e) {
                Log.e("TAG", "接收到onError事件==" + e.toString());
            }

            @Override
            public void onComplete() {
                Log.e("TAG", "接收到onComplete事件");
            }
        });
    }
}

打印log结果:接收了 test1、test2、test3和onComplete事件

1525326244(1).jpg

关注③ 可采用 Disposable.dispose() 切断观察者 与 被观察者 之间的连接

public class MainActivity extends AppCompatActivity {
    // 定义Disposable类变量
    private Disposable mDisposable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Exception {
                emitter.onNext("test1");
                emitter.onNext("test2");
                emitter.onNext("test3");
                emitter.onNext("test4");
                emitter.onComplete();
            }
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                //  对Disposable类变量赋值
                mDisposable=d;
                Log.e("TAG", "开始接收上游可观察者(Observable)的事件");
            }

            @Override
            public void onNext(@NonNull String s) {
                Log.e("TAG", "接收到Next事件==" + s);
                /**
                 * 当接收的事件为test2的时候,切断观察者 与 可观察者 之间的连接
                 * 即观察者 不再继续 接收 可观察者发送的事件,但可观察者还是可以继续发送事件
                 * 
                 * 就好比可观察者为上游的出水水管,观察者为下游接水水管,中间通过Subscribe连接,现在将两个水管的交接出去掉
                 * 下游不再可以接收水,上游却可以继续出水
                 */

                if (s.equals("test2")){
                    mDisposable.dispose();
                }
            }

            @Override
            public void onError(@NonNull Throwable e) {
                Log.e("TAG", "接收到onError事件==" + e.toString());
            }

            @Override
            public void onComplete() {
                Log.e("TAG", "接收到onComplete事件");
            }
        });
    }
}

Log打印结果:下图可看出,当接收的事件为test2事件后,观察者不再接收后面的事件,连onComplete事件也不再接收,但此时,可观察者依然在继续发送事件

1525327664(1).jpg

3.2、RxJava其他简单创建用法

3.2.1、just(Object)的使用

1、快速的创建可观察者对象
2、直接发送 传入的事件(参数)转化为Observable对象
3、最多只能发送10个参数
4、将传入的参数依次发射出来
5、与 fromXxx( T[] ) / fromXxx( Iterable<? extends T> )用法很接近,参数前者是一个一个的,后者是数组T[]的形式 / Iterable 拆分成的具体对象
6、不那么准确的说 fromArray( T[] )just(Object) 的加强版

public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Observable
                .just("test1","test2","test3","test4","test5","test6","test7","test8","test9","test10")
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        Log.e("TAG", "开始接收上游可观察者(Observable)的事件");
                    }

                    @Override
                    public void onNext(@NonNull String s) {
                        Log.e("TAG", "接收到Next事件==" + s);

                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        Log.e("TAG", "接收到onError事件==" + e.toString());
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "接收到onComplete事件");
                    }
                });
    }
}

log打印结果:

1525331916(1).jpg

3.2.2、fromArray( T [ ] )的简单使用

1、 可发送10个以上事件(数组形式)
2、不那么准确的说 fromArray( T[] )just(Object) 的加强版
3、与 fromXxx( T[] ) / fromXxx( Iterable<? extends T> )用法很接近
4、与 fromIterable( list )用法很接近
5、fromArray( T[] ) 的参数是一个数组,将数组中的数据转换为一个个Observable对象
6、若传入一个list集合,会直接把list当做一个数据元素,转换为Observable对象发送出去,示例看关注④

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        /**
         *  设置需要传入的数组
         * 快速创建Observable对象
         */
        String[] items = {"test1","test2","test3","test4","test5","test6","test7","test8","test9","test10"};
        Observable
                .fromArray(items)
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        Log.e("TAG", "开始接收上游可观察者(Observable)的事件");
                    }

                    @Override
                    public void onNext(@NonNull String s) {
                        Log.e("TAG", "接收到Next事件==" + s.toString());

                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        Log.e("TAG", "接收到onError事件==" + e.toString());
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "接收到onComplete事件");
                    }
                });

log打印结果 :

1525334420(1).jpg

关注④ fromArray() 传入一级list集合,会将这个集合转换为一个Observable对象

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        /**
         *  设置需要传入的数组
         * 快速创建Observable对象
         */
        String[] items = {"test1","test2","test3","test4","test5","test6","test7","test8","test9","test10"};
        List<String> list=new ArrayList<>();
        for (String item:items){
            list.add(item);
        }
        
        Observable
                .fromArray(list)
                .subscribe(new Observer<List>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        Log.e("TAG", "开始接收上游可观察者(Observable)的事件");
                    }

                    @Override
                    public void onNext(@NonNull List s) {
                        Log.e("TAG", "接收到Next事件==" + s.toString());

                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        Log.e("TAG", "接收到onError事件==" + e.toString());
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "接收到onComplete事件");
                    }
                });

下面是参数为 数组 与参数为 list 的log打印结果:

1525334859(1).jpg

3.2.2.1、额外说明:此处参考文章来自---------Android Rxjava:这是一篇 清晰 & 易懂的Rxjava 入门教程

    public final Disposable subscribe() {}
    // 表示观察者不对被观察者发送的事件作出任何响应(但可观察者还是可以继续发送事件)

    public final Disposable subscribe(Consumer<? super T> onNext) {}
    // 表示观察者只对被观察者发送的Next事件作出响应
    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {} 
    // 表示观察者只对被观察者发送的Next事件 & Error事件作出响应

    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete) {}
    // 表示观察者只对被观察者发送的Next事件、Error事件 & Complete事件作出响应

    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Consumer<? super Disposable> onSubscribe) {}
    // 表示观察者只对被观察者发送的Next事件、Error事件 、Complete事件 & onSubscribe事件作出响应

    public final void subscribe(Observer<? super T> observer) {}
    // 表示观察者对被观察者发送的任何事件都作出响应

3.2.3、fromIterable( list )的简单使用

与前面几个类似,参数是集合list,用法跟前面几个一样,这里就不说明了,需要的话就看前面几个的说明

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        /**
         *  设置需要传入的数组
         * 快速创建Observable对象
         */
        String[] items = {"test1","test2","test3","test4","test5","test6","test7","test8","test9","test10"};
        List<String> list=new ArrayList<>();
        for (String item:items){
            list.add(item);
        }

        Observable
                .fromIterable(list)
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        Log.e("TAG", "开始接收上游可观察者(Observable)的事件");
                    }

                    @Override
                    public void onNext(@NonNull String s) {
                        Log.e("TAG", "接收到Next事件==" + s);

                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        Log.e("TAG", "接收到onError事件==" + e.toString());
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "接收到onComplete事件");
                    }
                });

log打印结果:

image.png

3.3、defer()的简单使用

1、在经过了x秒后,需要自动执行y操作
2、每隔x秒后,需要自动执行y操作

3.4、timer()的简单使用

1、延迟指定时间后,发送1个数值0(Long类型)
2、原理:延迟指定时间后,调用一次 onNext(0)
3、发送一个0,一般用于检测
4、timer操作符默认运行在一个新线程上,既然可以默认也可以自定义,timer(long,TimeUnit,Scheduler)第三个参数可自定义线程,指定timer的运行线程

// 延迟1s后,发送一个long类型数值
        Observable.timer(1, TimeUnit.SECONDS)
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.e("TAG", "开始连接");
                    }

                    @Override
                    public void onNext(Long value) {
                        Log.e("TAG", "onNext=="+ value  );
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("TAG", "接收到onError事件");
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "接收到onComplete事件");
                    }

                });

log打印结果:先是打印 开始连接 ,1s后,再打印onNext==0 接收到onComplete事件

1525339570(1).jpg

3.5、interval()的简单使用

1、快速创建1个被观察者对象(Observable
2、每隔指定时间 就发送 事件
3、发送的事件序列 = 从0开始、无限递增1的的整数序列

         /**
         * 
         * 延迟3s后发送事件,每隔1秒产生1个数字(从0开始递增1,无限个)
         * 
         * 
         * 参数1 = 第1次延迟时间;
         * 参数2 = 间隔时间数字;
         * 参数3 = 时间单位;
         */
        Observable.interval(3,1,TimeUnit.SECONDS)
                
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.e("TAG", "开始连接");
                    }
                    // 默认最先调用复写的 onSubscribe()

                    @Override
                    public void onNext(Long value) {
                        Log.e("TAG", "接收onNext事件"+ value  );
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("TAG", "接收onError事件"+e.toString());
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "接收onComplete事件");
                    }

                });

log打印结果:第一次打印开始连接 ,3s后,打印 接收onNext事件0, 之后每隔一秒打印一个接收onNext事件1........N 无限递增

3.6、intervalRange()的简单使用

1、快速创建1个被观察者对象(Observable
2、每隔指定时间 就发送 事件,可指定发送的数据的数量
3、发送的事件序列 = 从0开始、递增1的的整数序列
4、. 作用类似于interval(),但可指定发送的数据的数量


 /**
         * 从3开始,一共发送10个事件,第1次延迟2s发送,之后每隔2秒产生1个数字
         * 
         * 
         * 参数1 = 事件序列起始点
         * 参数2 = 事件数量
         * 参数3 = 第1次事件延迟发送时间
         * 参数4 = 间隔时间数字
         * 参数5 = 时间单位
         */

        Observable.intervalRange(3,10,2, 1, TimeUnit.SECONDS)
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.e("TAG", " 开始连接");
                    }

                    @Override
                    public void onNext(Long value) {
                        Log.e("TAG", " 接收onNext事件"+ value  );
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("TAG", " 接收onError事件"+e.toString());
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", " 接收onComplete事件");
                    }

                });
1525341993(1).jpg

3.7、range()的简单使用

1、快速创建1个被观察者对象(Observable
2、连续发送 1个事件序列,可指定范围
3、发送的事件序列 = 从0开始、递增1的的整数序列
4、作用类似于intervalRange(),但区别在于:无延迟发送事件

        /**
         * 从4开始发送,每次发送事件递增1,一共发送5个事件
         *
         * 参数1 = 事件序列起始点
         * 参数2 = 事件数量
         * 注:若设置为负数,则会抛出异常
         */

        Observable.range(4,5)
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        Log.e("TAG", "开始连接");
                    }

                    @Override
                    public void onNext(Integer value) {
                        Log.e("TAG", "接收到了事件"+ value  );
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("TAG", "接收onError事件"+e.toString());
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "接收onComplete事件");
                    }

                });

log打印结果:

1525341057(1).jpg

4、RXJava常用操作符的简单使用*

4.1、变换操作符

①、map() 将事件序列中的对象或整个序列进行加工转换,将可观察者要发送的事件转换为任意的类型事件。
②、Flatmap()
③、ConcatMap()
④、Buffer()

4.1.1、Map()简单使用

1、说明: 将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列,不准确的说,就是 传进去的值被转换了,返回的返回值不同了,将可观察者要发送的事件转换为任意的类型事件。

Observable.create(new ObservableOnSubscribe<Integer>() {

                    // 可观察者发送事件 = 参数为整型 = 1、2、3
                    @Override
                    public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Exception {
                        emitter.onNext(1);
                        emitter.onNext(2);
                        emitter.onNext(3);
                    }
                })
                // 使用Map变换操作符中的Function函数对可观察者发送的事件
                // 进行统一变换:将整型变换成字符串类型
                .map(new Function<Integer, String>() {
                    @Override
                    public String apply(@NonNull Integer integer) throws Exception {
                        return "使用 Map变换操作符 将事件" + integer +"的参数从 整型"
                                +integer + " 变换成 字符串类型" + integer ;
                    }
                })
                .subscribe(new Consumer<String>() {
                    // 观察者接收事件时,是接收到变换后的事件 = 字符串类型
                    @Override
                    public void accept(String s) throws Exception {
                        Log.e("TAG", s);
                    }
                });

log打印结果:

1525402785(1).jpg

4.1.2、FlatMap()简单使用

  • 将被观察者发送的事件序列进行 拆分 & 单独转换,再合并成一个新的事件序列,最后再进行发送
  • 无序的将被观察者发送的整个事件序列进行变换
  // 采用RxJava基于事件流的链式操作
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
                emitter.onNext(4);
            }

            // 采用flatMap()变换操作符
        }).flatMap(new Function<Integer, ObservableSource<String>>() {
            @Override
            public ObservableSource<String> apply(Integer integer) throws Exception {
//                final List<String> list = new ArrayList<>();
//                for (int i = 0; i < 3; i++) {
//                    list.add("我是事件 " + integer + "拆分后的子事件" + i);
//                    // 通过flatMap中将可观察者发送的事件序列先进行拆分,再将每个事件转换为一个新的Observable,再发送给出去
//                    // 最终合并,再发送给被观察者
//                return Observable.fromIterable(list);
//                }

                //这里会生成新的可观察者,然后与观察者订阅,像一种代理机制,通过事件拦截和处理实现事件序列的变换。
                return Observable.just("事件 " + integer + " 转换成的子事件 " + "test"+integer);
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.e("TAG", s);
            }
        });

log打印结果:

image.png

4.1.3、concatMap()简单使用

  • 将被观察者发送的事件序列进行 拆分 & 单独转换,再合并成一个新的事件序列,最后再进行发送
  • 无序的将被观察者发送的整个事件序列进行变换
  • 用法和flatMap()相同,只是场景不同
  • 新合并生成的事件序列顺序是有序的,即 严格按照旧序列发送事件的顺序
 // 采用RxJava基于事件流的链式操作
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
                emitter.onNext(4);
            }

            // 采用concatMap()变换操作符
        }).concatMap(new Function<Integer, ObservableSource<String>>() {
            @Override
            public ObservableSource<String> apply(Integer integer) throws Exception {
                //                final List<String> list = new ArrayList<>();
                //                for (int i = 0; i < 3; i++) {
                //                    list.add("我是事件 " + integer + "拆分后的子事件" + i);
                //                    // 通过concatMap中将可观察者发送的事件序列先进行拆分,再将每个事件转换为一个新的Observable,再发送给出去
                //                    // 最终合并,再发送给被观察者
                //                return Observable.fromIterable(list);
                //                }

                //这里会生成新的可观察者,然后与观察者订阅,像一种代理机制,通过事件拦截和处理实现事件序列的变换。
                return Observable.just("事件 " + integer + " 转换成的子事件 " + "test"+integer);
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.e("TAG", s);
            }
        });

log打印结果:

image.png

4.1.4、Buffer()简单使用

  • 场景:缓存被观察者发送的事件
  • 作用:定期从可观察者(Obervable)需要发送的事件中 获取一定数量的事件 & 放到缓存区中,最终发送
// 被观察者 需要发送5个数字
        Observable.just(1, 2, 3, 4, 5)
                .buffer(3, 1) // 设置缓存区大小 & 步长
                // 缓存区大小 = 每次从被观察者中获取的事件数量
                // 步长 = 每次获取新事件的数量
                .subscribe(new Observer<List<Integer>>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }
                    @Override
                    public void onNext(List<Integer> stringList) {
                        //
                        Log.e("TAG", " 缓存区里的事件数量 = " +  stringList.size());
                        for (Integer value : stringList) {
                            Log.e("TAG", " 接收onNext事件 = " + value);
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("TAG", "接收onError事件" );
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "接收Complete事件");
                    }
                });

log打印结果:

image.png

4.2、concat() / concatArray()组合多个可观察者

① 组合多个被观察者一起发送数据,合并后 按发送顺序串行执行
concat() / concatArray()二者区别:组合被观察者的数量,即concat()组合被观察者数量≤4个,而concatArray()则可>4个

4.2.1、concat()

concat():组合多个被观察者(≤4个)一起发送数据

    // 串行执行
        Observable
                .concat(

                        Observable.just(1, 2, 3),
                        Observable.just(4, 5, 6),
                        Observable.just(7, 8, 9),
                        Observable.just(10, 11, 12)
                )
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(Integer value) {
                        Log.e("TAG", "接收到onNext事件==" + value);
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("TAG", "接收到onError事件"+e.toString());
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "接收到onComplete事件");
                    }
                });

log打印结果:

image.png

4.2.2、concatArray()

concat():组合多个被观察者(≤4个)一起发送数据
concatArray():组合多个被观察者一起发送数据(可>4个)

        // 串行执行
        Observable.concatArray(Observable.just(1, 2, 3),
                Observable.just(4, 5, 6),
                Observable.just(7, 8, 9),
                Observable.just(10, 11, 12),
                Observable.just(13, 14, 15))
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(Integer value) {
                        Log.e("TAG", "接收到了事件" + value);
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("TAG", "对Error事件作出响应");
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "对Complete事件作出响应");
                    }
                });

log打印结果:

image.png

4.3、merge() / mergeArray()简单使用

① 组合多个可观察者一起发送数据,合并后 按时间线并行执行
② 二者区别:组合可观察者的数量,即merge()组合可观察者数量≤4个,而mergeArray()则可>4个
③ 区别上述concat()操作符:同样是组合多个可观察者一起发送数据,但concat()操作符合并后是按发送顺序串行执行

4.3.1、merge()简单使用

merge():组合多个可观察者(≤ 4个)一起发送数据

//合并后按照时间线并行执行
        Observable.merge(
                Observable.intervalRange(0, 3, 1, 1, TimeUnit.SECONDS), // 从0开始发送、共发送3个数据、第1次事件延迟发送时间 = 1s、间隔时间 = 1s
                Observable.intervalRange(2, 3, 1, 1, TimeUnit.SECONDS)) // 从2开始发送、共发送3个数据、第1次事件延迟发送时间 = 1s、间隔时间 = 1s
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(Long value) {
                        Log.e("TAG", "接收到onNext事件"+ value  );
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("TAG", "接收到onError事件");
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "接收到onComplete事件");
                    }
                });

log打印结果:输出结果 = 事件0,事件2 -> 事件1,事件3 -> 事件2,事件4

image.png

4.3.2、mergeArray()简单使用

mergeArray():组合多个可观察者(≤ 4个)一起发送数据

Observable.mergeArray(
                Observable.intervalRange(0, 3, 1, 1, TimeUnit.SECONDS), // 从0开始发送、共发送3个数据、第1次事件延迟发送时间 = 1s、间隔时间 = 1s
                Observable.intervalRange(2, 3, 1, 1, TimeUnit.SECONDS)) // 从2开始发送、共发送3个数据、第1次事件延迟发送时间 = 1s、间隔时间 = 1s
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(Long value) {
                        Log.e("TAG", "mergeArray--接收到onNext事件"+ value  );
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("TAG", "mergeArray--接收到onError事件");
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "mergeArray--接收到onComplete事件");
                    }
                });

log打印结果:输出结果 = 事件0,事件2 -> 事件1,事件3 -> 事件2,事件4

image.png

4.4、concatDelayError() / mergeDelayError()简单使用

  • 使用concat()和merge()操作符时,其中1个可观察者发出onError事件,则会马上终止其他可观察者继续发送事件,如果希望onError事件推迟到其他可观察者发送事件结束才再触发发送onError事件,可使用concatDelayError()或者mergeDelayError操作符来解决
Observable.concat( //没有使用concatDelayError()的情况 
                
                Observable.create(new ObservableOnSubscribe<Integer>() {
                    @Override
                    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {

                        emitter.onNext(1);
                        emitter.onError(new NullPointerException()); // 发送Error事件,因为无使用concatDelayError,所以第2个Observable将不会发送事件
                        emitter.onNext(2);
                        emitter.onNext(3);
                        emitter.onComplete();
                    }
                }),
                Observable.just(4, 5, 6))//没有使用了concatDelayError(),事件4、5、6在onError事件后不再发射
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }
                    @Override
                    public void onNext(Integer value) {
                        Log.e("TAG", " 接收到事件 "+ value  );
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("TAG", "接收到onError事件");
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "接收到onComplete事件");
                    }
                });
        
 
                Observable.concatArrayDelayError(//使用了concatDelayError()的情况
                        
                        Observable.create(new ObservableOnSubscribe<Integer>() {
                            @Override
                            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {

                                emitter.onNext(1);
                                emitter.onError(new NullPointerException()); // 发送Error事件,因为使用了concatDelayError,所以第2个Observable将会发送事件,等发送完毕后,再发送错误事件
                                emitter.onNext(2);
                                emitter.onNext(3);
                                emitter.onComplete();
                            }
                        }),
                        Observable.just(4, 5, 6))//使用了concatDelayError(),事件4、5、6在onError事件后可以发射
                        .subscribe(new Observer<Integer>() {
                            @Override
                            public void onSubscribe(Disposable d) {

                            }
                            @Override
                            public void onNext(Integer value) {
                                Log.e("TAG", "接收到了事件"+ value  );
                            }

                            @Override
                            public void onError(Throwable e) {
                                Log.e("TAG", "接收到了onError事件");
                            }

                            @Override
                            public void onComplete() {
                                Log.e("TAG", "接收到了onComplete事件");
                            }
                        });

log打印结果:下图可知,不适用concatDelayonError时,事件4、5、6没有被发射出来,而使用concatDelayonError时,会发射玩所有事件后,在发射onError事件,就是onError事件被延迟发射了,此情况mergeDelayError雷同,代码就省略了

image.png

4.5 合并多个事件Zip()的简单使用

① 该类型的操作符主要是对多个被观察者中的事件进行合并处理
② 合并 多个被观察者(Observable)发送的事件,生成一个新的事件序列(即组合过后的事件序列),并最终发送
③ 事件组合方式 = 严格按照原先事件序列 进行对位合并
④ 最终合并的事件数量 = 多个被观察者(Observable)中数量最少的数量

//创建第1个被观察者
        Observable<Integer> observable1 = Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                Log.e("TAG", "可观察者1发送了事件 1");
                emitter.onNext(1);
                // 为了方便展示效果,所以在发送事件后加入2s的延迟
                Thread.sleep(2000);

                Log.e("TAG", "可观察者1发送了事件2");
                emitter.onNext(2);
                Thread.sleep(2000);

                Log.e("TAG", "可观察者1发送了事件3");
                emitter.onNext(3);
                Thread.sleep(2000);

                Log.e("TAG", "可观察者1发送了事件4");
                emitter.onNext(4);
                Thread.sleep(2000);

                emitter.onComplete();
            }
        }).subscribeOn(Schedulers.io()); // 设置可观察者1    在线程1中执行


        //创建第2个可观察者
        Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                Log.e("TAG", "可观察者 2 发送了事件 A ");
                emitter.onNext("A");
                Thread.sleep(2000);

                Log.e("TAG", "可观察者 2 发送了事件 B ");
                emitter.onNext("B");
                Thread.sleep(2000);

                Log.e("TAG", "可观察者 2 发送了事件 C ");
                emitter.onNext("C");
                Thread.sleep(2000);

                Log.e("TAG", "可观察者 2 发送了事件 D ");
                emitter.onNext("D");
                Thread.sleep(2000);

                emitter.onComplete();
            }
        }).subscribeOn(Schedulers.newThread());// 设置可观察者 2    在 线程2中执行
        // 假设不作线程控制,则该两个被观察者会在同一个线程中工作,即发送事件存在先后顺序,而不是同时发送

        // 使用zip变换操作符进行事件合并
        // 注:创建BiFunction对象传入的3个参数 ==可观察者1的数据类型  可观察者2的数据类型   合并后数据的数据类型
        Observable.zip(observable1, observable2, new BiFunction<Integer, String, String>() {
            @Override
            public String apply(Integer integer, String string) throws Exception {
                return integer + string;
            }
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.e("TAG", "onSubscribe");
            }

            @Override
            public void onNext(String value) {
                Log.e("TAG", "最终接收到的事件 =  " + value);
            }

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

            @Override
            public void onComplete() {
                Log.e("TAG", "onComplete");
            }
        });

log打印结果:

1525422593(1).jpg

4.6 combineLatest()的简单使用

① 当两个Observables中的任何一个发送了数据后,将先发送了数据的Observables 的最新(最后)一个数据 与 另外一个Observable发送的每个数据结合,最终基于该函数的结果发送数据
② 与Zip()的区别:Zip() = 按个数合并,即1对1合并;CombineLatest() = 按时间合并,即在同一个时间点上合并

Observable.combineLatest(
                Observable.just(1L, 2L, 3L), // 第1个发送数据事件的Observable
                Observable.intervalRange(0, 3, 2, 2, TimeUnit.SECONDS), // 第2个发送数据事件的Observable:从0开始发送、共发送3个数据、第1次事件延迟发送时间 = 2s、间隔时间 = 2s
                new BiFunction<Long, Long, Long>() {
                    @Override
                    public Long apply(Long o1, Long o2) throws Exception {
                        // o1 = 第1个Observable发送的最新(最后)1个数据
                        // o2 = 第2个Observable发送的每1个数据
                        Log.e("TAG", "合并的数据是: "+ "第一个  "+o1 + " "+ "第二个  "+o2);
                        return o1 + o2;
                        // 合并的逻辑 = 相加
                        // 即第1个Observable发送的最后1个数据 与 第2个Observable发送的每1个数据进行相加
                    }
                }).subscribe(new Consumer<Long>() {
            @Override
            public void accept(Long s) throws Exception {
                Log.e("TAG", "合并的结果是: "+s);
            }
        });

log打印结果:

image.png

4.6 collect()的简单使用

① 将被观察者Observable发送的数据事件收集到一个数据结构里

Observable.just(1, 2, 3 ,4, 5, 6)
                .collect(
                        // 1. 创建数据结构(容器),用于收集被观察者发送的数据
                        new Callable<ArrayList<Integer>>() {
                            @Override
                            public ArrayList<Integer> call() throws Exception {
                                return new ArrayList<>();
                            }
                            // 2. 对发送的数据进行收集
                        }, new BiConsumer<ArrayList<Integer>, Integer>() {
                            @Override
                            public void accept(ArrayList<Integer> list, Integer integer)
                                    throws Exception {
                                // 参数说明:list = 容器,integer = 后者数据
                                list.add(integer);
                                // 对发送的数据进行收集
                            }
                        }).subscribe(new Consumer<ArrayList<Integer>>() {
            @Override
            public void accept(@NonNull ArrayList<Integer> s) throws Exception {
                Log.e("TAG", "本次发送的数据是: "+s);

            }
        });

log打印结果:

image.png

4.7、startWith() / startWithArray()发送事件前追加发送事件

① 在一个被观察者发送事件前,追加发送一些数据 / 一个新的被观察者

 //在一个被观察者发送事件前,追加发送一些数据
        // 注:追加数据顺序 = 后调用先追加
        Observable.just(4, 5, 6)
                .startWithArray(1, 2, 3) // 追加多个数据 = startWithArray()
                .startWith(0)  // 追加单个数据 = startWith()
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(Integer value) {
                        Log.e("TAG", "接收到了事件" + value);
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("TAG", "对Error事件作出响应");
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "对Complete事件作出响应");
                    }
                });


        // 在一个被观察者发送事件前,追加发送被观察者 & 发送数据
        // 注:追加数据顺序 = 后调用先追加
        Observable.just(4, 5, 6)
                .startWith(Observable.just(1, 2, 3))
                .subscribe(new Observer<Integer>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(Integer value) {
                        Log.e("TAG", "接收到了事件" + value);
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e("TAG", "对Error事件作出响应");
                    }

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "对Complete事件作出响应");
                    }
                });

log打印结果:

image.png

4.8、count()统计发送事件数量

① 统计被观察者发送事件的数量

// 注:返回结果 = Long类型
        Observable.just(1, 2, 3, 4)
                .count()
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        Log.e("TAG", "发送的事件数量 =  "+aLong);

                    }
                });

log打印结果:

image.png

4.10、组合 / 合并操作符 总结

图片来自:https://www.jianshu.com/p/c2a7c03da16d

5、RxJava的线程控制(切换 / 调度 ):异步操作

① 指定 可观察者 (Observable) / 观察者(Observer) 的工作线程类型
② 线程控制(也称为调度 / 切换)功能性操作符中的:subscribeOn() 与 observeOn()
Observable.subscribeOn(Schedulers.Thread):指定被观察者 发送事件的线程(传入RxJava内置的线程类型)
Observable.observeOn(Schedulers.Thread):指定观察者 接收 & 响应事件的线程(传入RxJava内置的线程类型)
subscribeOn(Schedulers.newThread()) :指定被观察者 生产事件的线程
observeOn(AndroidSchedulers.mainThread()) :指定观察者 接收 & 响应事件的线程

5.1 指定可观察者 发射线程 subscribeOn()

若Observable.subscribeOn()多次指定可观察者 生产事件的线程,则只有第一次指定有效,其余的指定线程无效

observable.subscribeOn(Schedulers.newThread()) // 第一次指定被观察者线程 = 新线程
                .subscribeOn(AndroidSchedulers.mainThread()) // 第二次指定被观察者线程 = 主线程
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);

//被观察者的线程 = 第一次指定的线程 = 新的工作线程,第二次指定的线程(主线程)无效

5.2 指定观察者 接收线程 subscribeOn()

若Observable.observeOn()多次指定观察者 接收 & 响应事件的线程,则每次指定均有效,即每调用一次observeOn(),观察者的线程就会切换一次

Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Exception {

            }
        }).subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread()) // 第一次指定观察者线程 = 主线程
                .doOnNext(new Consumer<String>() { // 生产事件
                    @Override
                    public void accept(String string) throws Exception {
                        Log.d("TAG", "第一次观察者Observer的工作线程是: " + Thread.currentThread().getName());
                    }
                })
                .observeOn(Schedulers.newThread()) // 第二次指定观察者线程 = 新的工作线程
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(String s) throws Exception {
                        
                    }
                }); // 生产事件


        // 注:
        // 1. 整体方法调用顺序:观察者.onSubscribe()> 被观察者.subscribe()> 观察者.doOnNext()>观察者.onNext()>观察者.onComplete() 
        // 2. 观察者.onSubscribe()固定在主线程进行

log打印结果:

5.3、背压策略详情请看--关于 RxJava 最友好的文章系列

被观察者发送事件速度远快于观察者的处理速度的情况下,一种告诉上游的被观察者降低发送速度的策略

 // 步骤1:创建被观察者 =  Flowable
        Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
                Log.e("TAG", "发送事件 1");
                emitter.onNext(1);
                Log.e("TAG", "发送事件 2");
                emitter.onNext(2);
                Log.e("TAG", "发送事件 3");
                emitter.onNext(3);
                Log.e("TAG", "发送完成");
                emitter.onComplete();
            }
        }, BackpressureStrategy.ERROR)
                .subscribe(new Subscriber<Integer>() {
                    // 步骤2:创建观察者 =  Subscriber & 建立订阅关系

                    @Override
                    public void onSubscribe(Subscription s) {
                        Log.e("TAG", "onSubscribe");
                        s.request(3);
                    }

                    @Override
                    public void onNext(Integer integer) {
                        Log.e("TAG", "接收到了事件" + integer);
                    }

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

                    @Override
                    public void onComplete() {
                        Log.e("TAG", "onComplete");
                    }
                });

6、错误处理 使用代码示例与详细讲解

发送事件过程中,遇到错误时的处理机制,
网络请求失败,加载本地,重试等

操作符有

1、 onErrorReturn(): 遇到错误时,发送1个特殊事件 & 正常终止
①、可捕获在它之前发生的异常

2、 onErrorResumeNext(): 遇到错误时,发送1个新的Observable
①、onErrorResumeNext()拦截的错误 = Throwable;若需拦截Exception请用onExceptionResumeNext()
②、若onErrorResumeNext()拦截的错误 = Exception,则会将错误传递给观察者的onError方法

3、onExceptionResumeNext():遇到错误时,发送1个新的Observable
①、onExceptionResumeNext()拦截的错误 =Exception;若需拦截Throwable请用onErrorResumeNext()
②、若onExceptionResumeNext()拦截的错误 = Throwable,则会将错误传递给观察者的onError方法

4、retry(): 重试,即当出现错误时,让被观察者(Observable)重新发射数据
①、接收到onError()时,重新订阅 & 发送事件
②、ThrowableException都可拦截

5、retryUntil(): 出现错误后,判断是否需要重新发送数据
①、若需要重新发送 & 持续遇到错误,则持续重试
②、作用类似于retry(Predicate predicate)
③、具体场景:类似于retry(Predicate predicate),唯一区别:返回 true 则不重新发送数据事件。

6、retryWhen(): 重试,即当出现错误时,让被观察者(Observable)重新发射数据
①、接收到 onError()时,重新订阅 & 发送事件
②、ThrowableException都可拦截

7、retryWhen(): 遇到错误时,将发生的错误传递给一个新的被观察者(Observable),并决定是否需要重新订阅原始被观察者(Observable)& 发送事件

7、重复发送 使用代码示例与详细讲解

重复不断地发送被观察者事件
对应操作符类型:repeat() &repeatWhen()

1、repeat(): 无条件地、重复发送 被观察者事件
①、具备重载方法,可设置重复创建次数

2、repeatWhen(): 有条件地、重复发送 被观察者事件

①、将原始 Observable 停止发送事件的标识(Complete() / Error())转换成1个 Object类型数据传递给1个新被观察者(Observable),以此决定是否重新订阅 & 发送原来的 Observable
②、若新被观察者(Observable)返回1个Complete / Error事件,则不重新订阅 & 发送原来的 Observable
③、若新被观察者(Observable)返回其余事件时,则重新订阅 & 发送原来的 Observable

8、composeTransformer 消除重复代码

详细讲解看 1 2 3 这三篇文章

8.1、在使用RXJava与Retrofit请求网络时,遇到过这样的场景,在IO线程请求网络解析数据,接着返回主线程setData、更新View试图,代码如下:

.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);

8.2、这样肯定是没问题的,但是如果请求网络的次数多了,岂不是每个地方都要写一遍?,并且同时又不想去破环RX的链式结构,怎么办呢,有一个不是唯一的办法,就是使用操作符

RetrofitClient.getData("网络接口URL")
.requestNetData("参数1","参数2")
.compose(CommonTransformer())//自定义ObservableTransformer,完成线程切换
.subscribe(subscriber);

就是用 .compose(schedulersTransformer()) 这一行一行代码就完成了线程切换,代替了.subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread())这段代码

8.3、实现ObservableTransformer,完成线程切换,然后使用compose()操作符

/**
 * ================================================
 * Created by ${chenyuexueer}
 * 说明:实现ObservableTransformer,完成线程切换,使用compose()操作符
 * ================================================
 */
Observable.Transformer schedulersTransformer() {
        return new Observable.Transformer() {
            @Override
            public Object call(Object observable) {
                return ((Observable)  observable).subscribeOn(Schedulers.io())
                        .unsubscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());
            }
        };
    }
//一行代码搞定,使用情况如下:
//observable.compose (schedulersTransformer()).subscribe(subscriber)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容

  • 我从去年开始使用 RxJava ,到现在一年多了。今年加入了 Flipboard 后,看到 Flipboard 的...
    Jason_andy阅读 5,384评论 7 62
  • 转一篇文章 原地址:http://gank.io/post/560e15be2dca930e00da1083 前言...
    jack_hong阅读 883评论 0 2
  • 前言我从去年开始使用 RxJava ,到现在一年多了。今年加入了 Flipboard 后,看到 Flipboard...
    占导zqq阅读 9,125评论 6 151
  • 最近项目里面有用到Rxjava框架,感觉很强大的巨作,所以在网上搜了很多相关文章,发现一片文章很不错,今天把这篇文...
    Scus阅读 6,794评论 2 50
  • 删除
    帅小冰阅读 584评论 1 4