RxJava Creating Observables(创建操作符)

RxJava系列教程:

1. RxJava使用介绍 【视频教程】
2. RxJava操作符
  • Creating Observables(Observable的创建操作符) 【视频教程】
  • Transforming Observables(Observable的转换操作符) 【视频教程】
  • Filtering Observables(Observable的过滤操作符) 【视频教程】
  • Combining Observables(Observable的组合操作符) 【视频教程】
  • Error Handling Operators(Observable的错误处理操作符) 【视频教程】
  • Observable Utility Operators(Observable的辅助性操作符) 【视频教程】
  • Conditional and Boolean Operators(Observable的条件和布尔操作符) 【视频教程】
  • Mathematical and Aggregate Operators(Observable数学运算及聚合操作符) 【视频教程】
  • 其他如observable.toList()、observable.connect()、observable.publish()等等; 【视频教程】
3. RxJava Observer与Subcriber的关系 【视频教程】
4. RxJava线程控制(Scheduler) 【视频教程】
5. RxJava 并发之数据流发射太快如何办(背压(Backpressure)) 【视频教程】


RxJava的强大之处,在于它提供了丰富且功能强悍的操作符,通过使用和组合这些操作符,你几乎能完成所有你想要完成的任务,举个例子如下:

现在有一个需求:app启动时显示一张图片(一般是app的logo),也就是我们所说的欢迎页,2-3秒后自动跳转到主页面。这不就是几乎每个app都有的启动页需求吗?几乎不用思考,代码如下:

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

        ImageView view = (ImageView) findViewById(R.id.iv_welcome);
        view.setImageResource(R.drawable.welcome);
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                finish();
            }
        },2000);
    }

使用RxJava的代码实现如下:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);

        ImageView view = (ImageView) findViewById(R.id.iv_welcome);
        view.setImageResource(R.drawable.welcome);
        Observable.timer(2, TimeUnit.SECONDS, AndroidSchedulers.mainThread()).map(l->{
            startActivity(new Intent(this, MainActivity.class));
            finish();
            return null;
        }).subscribe();
    }

这里的RxJava使用了两个操作符:一个是timer操作符,它的意思是延迟执行某个操作;一个是map操作符,它的意思是转换某个执行结果。
恩,好像除了写法不一样,也没看出RxJava有什么优势呢。好吧,继续往下看!


由于最近产品要做活动,为了在显著的位置把活动的内容显示给用户,经过讨论,就是在欢迎页停留2秒后,要跳转到活动内容的页面(也就是一张广告的图片)上,然后在活动内容的页面停留2-3秒,再跳转到主页面;

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);

        ImageView view = (ImageView) findViewById(R.id.iv_welcome);
        view.setImageResource(R.drawable.welcome);
        //开新线程从网络获取图片
        AsyncAdImageFromNet();

        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //mAdBitmapDrawable是从网络获取到的图片,如果获取到图片,则显示出来,否则直接跳转到主页面
                if(mAdBitmapDrawable != null){
                    view.setImageDrawable(mAdBitmapDrawable);
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                            finish();
                        }
                    }, 2000);
                } else {
                    startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                    finish();
                }
            }
        }, 2000);

    }

这段代码没有考虑离线情况,即没有网络的情况下是显示不出活动内容图片的,最好是在有网络的情况下就把图片下载到本地缓存起来,不管有没有网络都装载本地的缓存即可,改进后的代码如下:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);

        ImageView view = (ImageView) findViewById(R.id.iv_welcome);
        view.setImageResource(R.drawable.welcome);
        //本地图片缓存路径
        File localBitmapFile = new File(getLocalBitmapPath());
        if(localBitmapFile.exists())
            mAdBitmapDrawable = BitmapFactory.decodeFile(localBitmapFile);
        //开新线程从网络获取图片
        AsyncAdImageFromNet();

        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //mAdBitmapDrawable是本地缓存获取到的图片,如果获取到图片,则显示出来,否则直接跳转到主页面
                if(mAdBitmapDrawable != null){
                    view.setImageDrawable(mAdBitmapDrawable);
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                            finish();
                        }
                    }, 2000);
                } else {
                    startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                    finish();
                }
            }
        }, 2000);

    }

仔细一看,代码还是有问题,加载本地缓存图片,如果图片比较大,就会阻塞主线程,最好是把加载本地缓存图片放在一个线程中执行,代码真是越写越乱,我们看看使用RxJava是怎么做的呢?

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);

        ImageView view = (ImageView) findViewById(R.id.iv_welcome);
        view.setImageResource(R.mipmap.welcome);

        Observable.mergeDelayError(
                //在新线程中加载本地缓存图片
                loadBitmapFromLocal().subscribeOn(Schedulers.io()),
                //在新线程中加载网络图片
                loadBitmapFromNet().subscribeOn(Schedulers.newThread()),
                Observable.timer(3,TimeUnit.SECONDS).map(c->null))
                //每隔2秒获取加载数据
                .sample(2, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
                .flatMap(r->{
                    if(r==null)  //如果没有获取到图片,直接跳转到主页面
                        return Observable.empty();
                    else { //如果获取到图片,则停留2秒再跳转到主页面
                        view.setImageDrawable(r);
                        return Observable.timer(2, TimeUnit.SECONDS);
                    }
                }).subscribe(
                r->{
                },
                e->{
                    startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                    finish();
                },
                ()->{
                    startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                    finish();
                }
        );
    }

这里使用了几个操作符:首先是mergeDelayError,它的意思是合并几个不同的Observable;sample的意思是每隔一段时间就进行采样,在时间间隔范围内获取最后一个发布的Observable; flatMap的意思是把某一个Observable转换成另一个Observable。

可以看到,使用了RxJava,整个代码思路很清晰,不用考虑底层的线程同步、异步通知等内容,把主要精力都集中在如何实现业务上,这就是响应式函数编程的魅力!

操作符分类

通过上面的例子,大家应该看到了RxJava操作符的威力,下面我按类别把常用操作符分别介绍,其实很多内容都是来自于ReactiveX的官方网站,英文比较好的朋友可以参考(http://reactivex.io/)。
按照官方的分类,操作符大致分为以下几种:

  • Creating Observables(Observable的创建操作符),比如:Observable.create()、Observable.just()、Observable.from()等等;
  • Transforming Observables(Observable的转换操作符),比如:observable.map()、observable.flatMap()、observable.buffer()等等;
  • Filtering Observables(Observable的过滤操作符),比如:observable.filter()、observable.sample()、observable.take()等等;
  • Combining Observables(Observable的组合操作符),比如:observable.join()、observable.merge()、observable.combineLatest()等等;
  • Error Handling Operators(Observable的错误处理操作符),比如:observable.onErrorResumeNext()、observable.retry()等等;
  • Observable Utility Operators(Observable的功能性操作符),比如:observable.subscribeOn()、observable.observeOn()、observable.delay()等等;
  • Conditional and Boolean Operators(Observable的条件操作符),比如:observable.amb()、observable.contains()、observable.skipUntil()等等;
  • Mathematical and Aggregate Operators(Observable数学运算及聚合操作符),比如:observable.count()、observable.reduce()、observable.concat()等等;
  • 其他如observable.toList()、observable.connect()、observable.publish()等等;

创建型操作符

Create

create操作符是所有创建型操作符的“根”,也就是说其他创建型操作符最后都是通过create操作符来创建Observable的,其流程图例如下:
这里写图片描述

示例代码:

Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> observer) {
        try {
            if (!observer.isUnsubscribed()) {
                for (int i = 1; i < 5; i++) {
                    observer.onNext(i);
                }
                observer.onCompleted();
            }
        } catch (Exception e) {
            observer.onError(e);
        }
    }
 } ).subscribe(new Subscriber<Integer>() {
        @Override
        public void onNext(Integer item) {
            System.out.println("Next: " + item);
        }

        @Override
        public void onError(Throwable error) {
            System.err.println("Error: " + error.getMessage());
        }

        @Override
        public void onCompleted() {
            System.out.println("onCompleted.");
        }
    });

运行结果如下:

Next: 1 
Next: 2 
Next: 3 
Next: 4 
onCompleted.

在使用create操作符时,最好要在回调的call函数中增加isUnsubscribed的判断,以便在subscriber在取消订阅时不会再执行call函数中相关代码逻辑,从而避免导致一些意想不到的错误出现;

From

from操作符是把其他类型的对象和数据类型转化成Observable,其流程图例如下:
这里写图片描述

  • 将一个Iterable, 一个Future, 或者一个数组转换成一个Observable。
  • 在RxJava中,from操作符可以转换Future、Iterable和数组。对于Iterable和数组,产生的Observable会发射Iterable或数组的每一项数据
  • 对于Future,它会发射Future.get()方法返回的单个数据。from方法有一个可接受两个可选参数的版本,分别指定超时时长和时间单位。如果过了指定的时长Future还没有返回一个值,这个Observable会发射错误通知并终止。
  • from默认不在任何特定的调度器上执行。然而你可以将Scheduler作为可选的第二个参数传递给Observable,它会在那个调度器上管理这个Future。
  • Javadoc: from(array)
  • Javadoc: from(Iterable)
  • Javadoc: from(Future)
  • Javadoc: from(Future,Scheduler)
  • Javadoc: from(Future,timeout, timeUnit)

示例代码:

Integer[] items = { 0, 1, 2, 3, 4, 5 };
Observable myObservable = Observable.from(items);

myObservable.subscribe(
    new Action1<Integer>() {
        @Override
        public void call(Integer item) {
            System.out.println(item);
        }
    },
    new Action1<Throwable>() {
        @Override
        public void call(Throwable error) {
            System.out.println("Error encountered: " + error.getMessage());
        }
    },
    new Action0() {
        @Override
        public void call() {
            System.out.println("onCompleted");
        }
    }
);

运行结果如下:

0 
1 
2 
3 
4 
5 
onCompleted

Just

just操作符也是把其他类型的对象和数据类型转化成Observable,它和from操作符很像,只是方法的参数有所差别,其流程图例如下:
这里写图片描述
示例代码:

Observable.just(1, 2, 3)
          .subscribe(new Subscriber<Integer>() {
        @Override
        public void onNext(Integer integer) {
            System.out.println("Next: " + integer);
        }

        @Override
        public void onError(Throwable error) {
            System.err.println("Error: " + error.getMessage());
        }

        @Override
        public void onCompleted() {
            System.out.println("onCompleted");
        }
    });

运行结果如下:

Next: 1 
Next: 2 
Next: 3 
onCompleted

Defer

defer操作符是直到有订阅者订阅时,才通过Observable的工厂方法创建Observable并执行,defer操作符能够保证Observable的状态是最新的,其流程实例如下:
这里写图片描述
下面通过比较defer操作符和just操作符的运行结果作比较:

int i=10;
Observable justObservable = Observable.just(i);
i=12;
Observable deferObservable = Observable.defer(new Func0<Observable<Object>>() {
       @Override
       public Observable<Object> call() {
           return Observable.just(i);
       }
   });
  i=15;

  justObservable.subscribe(new Subscriber() {
      @Override
      public void onCompleted() {

      }

      @Override
      public void onError(Throwable e) {

      }

      @Override
      public void onNext(Object o) {
          System.out.println("just result:" + o.toString());
      }
  });

  deferObservable.subscribe(new Subscriber() {
      @Override
      public void onCompleted() {

      }

      @Override
      public void onError(Throwable e) {

      }

      @Override
      public void onNext(Object o) {
          System.out.println("defer result:" + o.toString());
      }
  });   

运行结果如下:

just result:10 
defer result:15

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

Interval

这里写图片描述

  • Interval操作符返回一个Observable,它按固定的时间间隔发射一个无限递增的整数序列;
  • 它接受一个表示时间间隔的参数和一个表示时间单位的参数
  • 还有一个版本的interval返回一个Observable,它在指定延迟之后先发射一个零值,然后再按照指定的时间间隔发射递增 的数字。这个版本的interval在RxJava 1.0.0中叫做timer,但是那个方法已经不建议使用了,因为一个名叫interval的操作符有同样的功能。
  • interval默认在computation调度器上执行。你也可以传递一个可选的Scheduler参数来指定调度器。

示例代码:

//以秒为单位,每隔1秒发射一个数据
        Observable.interval(1, TimeUnit.SECONDS)
        .subscribe(new Subscriber<Long>() {
            @Override
            public void onCompleted() {
                System.out.println("onCompleted" );
            }
            @Override
            public void onError(Throwable e) {
            }
            @Override
            public void onNext(Long aLong) {
                System.out.println("interval:" + aLong);
            }
        });

运行结果如下:

interval:0
interval:1
interval:2
interval:3
......

Range

这里写图片描述
- range操作符创建一个发射指定范围的整数序列的Observable,你可以指定范围的起始和长度。
- 它接受两个参数,一个是范围的起始值,一个是范围的数据的数目。如果你将第二个参数设为0,将导致Observable不发射任何数据(如果设置为负数,会抛异常)
- range默认不在任何特定的调度器上执行。有一个变体可以通过可选参数指定Scheduler。

示例代码:

Observable.range(1, 6).subscribe(new Subscriber<Integer>() {
            @Override
            public void onNext(Integer item) {
                System.out.println("Next: " + item); 
            }
            @Override
            public void onError(Throwable error) {
            }
            @Override
            public void onCompleted() {
                System.out.println("onCompleted"); 
            }
        });

运行结果如下:

Next: 1
Next: 2
Next: 3
Next: 4
Next: 5
Next: 6
onCompleted

Repeat

这里写图片描述
- repeat重复地发射数据。某些实现允许你重复的发射某个数据序列,还有一些允许你限制重复的次数。
- 它不是创建一个Observable,而是重复发射原始Observable的数据序列,这个序列或者是无限的,或者通过repeat(n)指定重复次数。
- repeat操作符默认在trampoline调度器上执行。有一个变体可以通过可选参数指定Scheduler。

示例代码:

//重复5次发送数据1
Observable.just(1).repeat(5).subscribe(new Subscriber<Integer>() {
    @Override
    public void onNext(Integer item) {
        System.out.println("Next: " + item); 
    }
    @Override
    public void onError(Throwable error) {
        System.err.println("Error: " + error.getMessage());
    }
    @Override
    public void onCompleted() {
        System.out.println("onCompleted"); 
    }
});

运行结果如下:

Next: 1
Next: 1
Next: 1
Next: 1
Next: 1
onCompleted

Timer

这里写图片描述
- timer操作符创建一个在给定的时间段之后返回一个特殊值的Observable
- timer返回一个Observable,它在延迟一段给定的时间后发射一个简单的数字0
- timer操作符默认在computation调度器上执行。有一个变体可以通过可选参数指定Scheduler

示例代码:

SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        String beginTime = sdf.format(new Date());
        System.out.println("beginTime : " + beginTime); 
        Observable.timer(2, TimeUnit.SECONDS)//从0开始发射数据
        .subscribe(new Subscriber<Long>() {
            @Override
            public void onNext(Long item) {
                //2秒后发射了一个数据
                System.out.println("Next: " + item); 
                String endTime =  sdf.format(new Date());
                System.out.println("endTime :" + endTime); 
            }
            @Override
            public void onError(Throwable error) {
                System.err.println("Error: " + error.getMessage());
            }
            @Override
            public void onCompleted() {
                System.out.println("onCompleted"); 
            }
        });

运行结果如下:

beginTime : 16:15:12
Next: 0
endTime :16:15:14
onCompleted
  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值