RxJava使用方法简析

Posted FightSeeker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RxJava使用方法简析相关的知识,希望对你有一定的参考价值。

我们很懒,所以我们就开发了很多很多的框架,用来节省我们的工作量、工作时间。异步操作难免是避不开的,官方提供的Handler机制以及AsyncTask ,都能实现异步操作,但是代码随着逻辑的增多而变得复杂,看上去混乱不堪有时候简直,所以,简洁高效的代码也是我们的追求。因此,为了异步,为了简洁,RxJava应运而生,来解决了以上的问题。

1.RxJava 地址以及添加

github地址:

https://github.com/ReactiveX/RxJava

https://github.com/ReactiveX/RxAndroid

依赖库添加:

compile ‘io.reactivex:rxjava:1.1.6’

compile ‘io.reactivex:rxandroid:1.2.1’

2.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:基本实现

先来看一下最基础的用法,

Observable.create(new Observable.OnSubscribe<String>() 
            @Override
            public void call(Subscriber<? super String> subscriber) 
                Log.d(TAG, "call: threadId:"+Thread.currentThread().getId());
                subscriber.onStart();
                subscriber.onNext("Hello World!");
                subscriber.onCompleted();
            
        )
          .subscribe(new Observer<String>() 
              @Override
              public void onCompleted() 
                  Log.d(TAG, "onCompleted: threadId:"+Thread.currentThread().getId());
              

              @Override
              public void onError(Throwable e) 
                  Log.e(TAG, "onError: threadId:"+Thread.currentThread().getId());
              

              @Override
              public void onNext(String s) 
                  Log.d(TAG, "onNext: threadId:"+Thread.currentThread().getId());
                  Log.i(TAG, "onNext: s = "+s);
              
          );

打印的结果如下所示:

09-03 11:43:57.322 16813-16813/? D/RxIavaDemo: call: threadId:1
09-03 11:43:57.322 16813-16813/? D/RxIavaDemo: onNext: threadId:1
09-03 11:43:57.322 16813-16813/? I/RxIavaDemo: onNext: s = Hello World!
09-03 11:43:57.322 16813-16813/? D/RxIavaDemo: onCompleted: threadId:1

从上可以看出,事件的处理和结果的接收都是在同一个线程里面处理的。但是,Rxjava的意义何在,异步呢?别急,看以下代码的处理,你就会发现了,异步原来是这么的简单。

        Log.i(TAG, "testFunction: threadId:"+Thread.currentThread().getId());
        Observable.create(new Observable.OnSubscribe<String>() 
            @Override
            public void call(Subscriber<? super String> subscriber) 
                Log.d(TAG, "call: threadId:"+Thread.currentThread().getId());
                subscriber.onStart();
                subscriber.onNext("Hello World!");
                subscriber.onCompleted();
            )
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<String>() 
                    @Override
                    public void onCompleted() 
                        Log.d(TAG, "onCompleted: threadId:" + Thread.currentThread().getId());
                    

                    @Override
                    public void onError(Throwable e) 
                        Log.e(TAG, "onError: threadId:" + Thread.currentThread().getId());
                    

                    @Override
                    public void onNext(String s) 
                        Log.d(TAG, "onNext: threadId:" + Thread.currentThread().getId());
                        Log.i(TAG, "onNext: s = " + s);
                    
                );

对比以上代码,我们简简单单的添加了两行代码:

 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())

那么接下俩看以下打印的结果如何:

09-03 11:51:11.354 18454-18454/? I/RxIavaDemo: testFunction: threadId:1
09-03 11:51:11.413 18454-18484/? D/RxIavaDemo: call: threadId:24076
09-03 11:51:11.444 18454-18454/? D/RxIavaDemo: onNext: threadId:1
09-03 11:51:11.444 18454-18454/? I/RxIavaDemo: onNext: s = Hello World!
09-03 11:51:11.444 18454-18454/? D/RxIavaDemo: onCompleted: threadId:1

看见了没,第二行threadId与其它的threadId很明显的不一样啊,说明我们在处理事件的时候,发生在了一个新的线程里面,而结果的接收,还是在主线程里面操作的。怎么样,只要添加两句话,异步立马就实现了,异步处理耗时操作,就是这么easy。

以上是RxJava的很基础很简单的一个用法,那么我们接着往下看,比如我们有一组需求把一个String数组的字符串,单个打印出来,我们用Rxjava怎么实现呢?看代码:

        Log.i(TAG, "testFunction: threadId:"+Thread.currentThread().getId());
        Observable.from(new String[]"one","two","three","four")
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<String>() 
                    @Override
                    public void onCompleted() 
                        Log.d(TAG, "onCompleted: threadId:" + Thread.currentThread().getId());
                    

                    @Override
                    public void onError(Throwable e) 
                        Log.e(TAG, "onError: threadId:" + Thread.currentThread().getId());
                    

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

Observable的from方法是给我们封装好的,我们直接拿来用就可以了。具体参数含义以后再说,打印的结果看下:

09-03 11:59:40.799 20463-20463/? I/RxIavaDemo: testFunction: threadId:1
09-03 11:59:40.838 20463-20463/? I/RxIavaDemo: onNext: s = one
09-03 11:59:40.838 20463-20463/? I/RxIavaDemo: onNext: s = two
09-03 11:59:40.838 20463-20463/? I/RxIavaDemo: onNext: s = three
09-03 11:59:40.838 20463-20463/? I/RxIavaDemo: onNext: s = four
09-03 11:59:40.838 20463-20463/? D/RxIavaDemo: onCompleted: threadId:1

再来看一个官方提供的方法:

        Log.i(TAG, "testFunction: threadId:"+Thread.currentThread().getId());
        Observable.just("one","two","three","four")
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<String>() 
                    @Override
                    public void onCompleted() 
                        Log.d(TAG, "onCompleted: threadId:" + Thread.currentThread().getId());
                    

                    @Override
                    public void onError(Throwable e) 
                        Log.e(TAG, "onError: threadId:" + Thread.currentThread().getId());
                    

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

打印结果如下:

09-03 14:06:32.051 9822-9822/? I/RxIavaDemo: testFunction: threadId:1
09-03 14:06:32.089 9822-9822/? I/RxIavaDemo: onNext: s = one
09-03 14:06:32.089 9822-9822/? I/RxIavaDemo: onNext: s = two
09-03 14:06:32.089 9822-9822/? I/RxIavaDemo: onNext: s = three
09-03 14:06:32.089 9822-9822/? I/RxIavaDemo: onNext: s = four
09-03 14:06:32.089 9822-9822/? D/RxIavaDemo: onCompleted: threadId:1

和上面的from一样,结果并无二致。

2-2:转换

以上的都是小儿科,现在最牛逼的地方来了。比如说,我想把一组字符串“1”,“2”,“3”,“4”转成int类型,该咋办呢?别急,看Rxjava是如何做到的,

        Log.i(TAG, "testFunction: threadId:"+Thread.currentThread().getId());
        Observable.just("1","2","3","4")
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .map(new Func1<String, Integer>() 

                    @Override
                    public Integer call(String s) 
                        return Integer.parseInt(s);
                    
                )
                .subscribe(new Action1<Integer>() 
                    @Override
                    public void call(Integer integer) 
                        Log.i(TAG, "call: integer = "+integer);
                    
                );

很简单,添加一个map函数,在里面做string—>int类型的转换。下面看一下打印结果如何:

09-03 14:17:42.964 11974-11974/? I/RxIavaDemo: testFunction: threadId:1
09-03 14:17:43.002 11974-11974/? I/RxIavaDemo: call: integer = 1
09-03 14:17:43.002 11974-11974/? I/RxIavaDemo: call: integer = 2
09-03 14:17:43.002 11974-11974/? I/RxIavaDemo: call: integer = 3
09-03 14:17:43.002 11974-11974/? I/RxIavaDemo: call: integer = 4

map转换,是一对一的转换,像示例当中,我们把string转成int,但是当我们需要一对多的转换,该怎么做呢?比如说,定义一个学生类:Student.java:

public class Student

        private String name;

        private List<String> courses;

        public String getName() 
            return name;
        

        public void setName(String name) 
            this.name = name;
        

        public List<String> getCourses() 
            return courses;
        

        public void setCourses(List<String> courses) 
            this.courses = courses;
        
    

里面定义了学生的名字,以及学生需要学习的课程数组。这个时候,我要打印课程列表的时候,该怎么办呢?首先,你可能会这样,

        Student student1 = new Student();
        student1.setName("Dandy");
        List<String> courses = new ArrayList<>();
        courses.add("语文");
        courses.add("数学");
        courses.add("英语");
        student1.setCourses(courses);

        Student student2 = new Student();
        student2.setName("Seeker");
        List<String> courses2 = new ArrayList<>();
        courses2.add("化学");
        courses2.add("地理");
        courses2.add("政治");
        student2.setCourses(courses2);

        Observable.just(student1,student2)
                .subscribe(new Action1<Student>() 
                    @Override
                    public void call(Student student) 
                        Log.i(TAG, "call: name = "+student.getName());
                        List<String> course = student.getCourses();
                        for(String str:course)
                            Log.i(TAG, "call: str = "+str);
                        
                    
                );

打印的结果如下:

09-03 14:44:30.318 16819-16819/? I/RxIavaDemo: testFunction: threadId:1
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: name = Dandy
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: str = 语文
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: str = 数学
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: str = 英语
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: name = Seeker
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: str = 化学
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: str = 地理
09-03 14:44:30.325 16819-16819/? I/RxIavaDemo: call: str = 政治

到时候想了,我不想执行一个for循环,该怎么办呢?上面提到的,转换,对了,我们做转换不就成,简单的通俗的一点理解,我转换一次,是list,那么我再转换一次不就是string了吗,怎么写呢?看下嘛:

        Observable.just(student1,student2)
                  .flatMap(new Func1<Student, Observable<String>>() 
                      @Override
                      public Observable<String> call(Student student) 
                          return Observable.from(student.getCourses());
                      
                  )
                .subscribe(new Action1<String>() 
                    @Override
                    public void call(String s) 
                        Log.i(TAG, "call: s = "+s);     
                    
                );

这里我们用到了flatmap这一函数,按通俗的一点理解:我们首先把Student转成了Observable,然后呢,又把student.getCourses()转成string挨个打印出来,结果如下:

09-03 14:54:30.340 18833-18833/? I/RxIavaDemo: testFunction: threadId:1
09-03 14:54:30.359 18833-18833/? I/RxIavaDemo: call: s = 语文
09-03 14:54:30.359 18833-18833/? I/RxIavaDemo: call: s = 数学
09-03 14:54:30.359 18833-18833/? I/RxIavaDemo: call: s = 英语
09-03 14:54:30.359 18833-18833/? I/RxIavaDemo: call: s = 化学
09-03 14:54:30.359 18833-18833/? I/RxIavaDemo: call: s = 地理
09-03 14:54:30.359 18833-18833/? I/RxIavaDemo: call: s = 政治

显然,我们要实现的功能做到了。
RxJava就是这么简单,就是这样简洁,就是这么异步,额,这个异步吗,只要你想,就一定可以实现,通过以上简单的用法示例,现总结流程如下:

总结不一定准确,但是我理解就行了,嘎嘎!

以上是关于RxJava使用方法简析的主要内容,如果未能解决你的问题,请参考以下文章

小儿抗病毒药有哪些

JS数字计算精度误差的解决方法

RxJava 和不受监控的下载

学习1

简析clone关键字与__clone()方法

学习27