RxJava2.x的集成及用法详解

目录

    • 目录
    • 主页
    • 中文资料
    • Rxjava是什么
    • 用途
    • 配置 添加依赖即可
    • 基本概念
        • 1. 被观察者. Observable
        • 2. 观察者. Observer
        • 3. 订阅. Subscribe
        • 4. 事件.
        • 5. Scheduler.
    • - 案例1
    • - 案例2
    • - 案例3

案例下载传送门

主页

  • Rxjava
  • RxAndroid

中文资料

  • 给 Android 开发者的 RxJava 详解
  • RxJava 2.x 教程

Rxjava是什么

首先要了解什么是观察者

Android 开发中一个比较典型的例子是点击监听器 OnClickListener 。对设置 OnClickListener 来说, View 是被观察者, OnClickListener 是观察者,二者通过 setOnClickListener() 方法达成订阅关系。订阅之后用户点击按钮的瞬间,Android Framework 就会将点击事件发送给已经注册的 OnClickListener 。采取这样被动的观察方式,既省去了反复检索状态的资源消耗,也能够得到最高的反馈速度。
RxJava2.x的集成及用法详解_第1张图片
如图所示,通过 setOnClickListener() 方法,Button 持有 OnClickListener 的引用(这一过程没有在图上画出);当用户点击时,Button 自动调用 OnClickListener 的 onClick() 方法。另外,如果把这张图中的概念抽象出来(Button -> 被观察者、OnClickListener -> 观察者、setOnClickListener() -> 订阅,onClick() -> 事件),就由专用的观察者模式(例如只用于监听控件点击)转变成了通用的观察者模式。如下图:
RxJava2.x的集成及用法详解_第2张图片

用途

  • 异步操作
  • 在逻辑复杂的情况下, 仍然可以让代码逻辑保持简洁

配置 添加依赖即可

com.android.tools.build:gradle 3.0 以上版本依赖在gradle 中的声明写法
    implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
    implementation 'io.reactivex.rxjava2:rxjava:2.x.y'com.android.tools.build:gradle 3.0 以下版本依赖在gradle 中的声明写法
    compile 'io.reactivex.rxjava2:rxandroid:2.0.2'
    compile  'io.reactivex.rxjava2:rxjava:2.x.y'

基本概念

1. 被观察者. Observable

    - 作用:决定什么时候出发时间以及出发怎样的事件
    - 创建方法:

        Observable.just (T t) //参数为单个的
        Observable.flapMap() //参数为多个的
        Observable.from (T [] t) //参数为数组
        Observable.from (Iterable  extends T>) //参数为Iterable (ArrayList的一种实现)

2. 观察者. Observer

    - 作用:当事件触发的时候将有怎样的行为
    - 实现类:

        Observer  \ Subscriber

3. 订阅. Subscribe

    - 作用:使被观察者与观察者建立联系
    -方法:       

           observable.subscribe(observer);
           observable.subscribe(subscriber);

4. 事件.

    onNext():普通事件
    onCompleted():时间队列完结
    onError():时间队列异常
    注意:onCompleted()onError()是互斥的,调用了其中一个另一个就不会被触发

5. Scheduler.

     - 作用:控制线程,指定某一段代码在哪个线程执行
     - 内置的Scheduler

        Schedulers.newThread(); //总是启用新线程,并在新的线程中执行操作
        Schedulers.io(); //I/O操作(读写文件、读写数据库、网络请求)所使用的线程。行为模式和newThread差不多,区别在于IO的内部实现的是一个无数量上线的线程池,可以重用空闲线程,因此多数情况下IO()比newThread()更有效率,不要把计算工作放在IO中,可以避免不必要的创建线程
        Schedulers.computation(); //计算使用的Schedulers,这个计算指的是CPU的密集型计算,既不会被I/O 等操作限制性能操作,例如图形的计算,这个Scheduler使用的固定的线程池,大小为CPU的核数。不要把IO操作放在computation()中,否则IO操作等待时间会浪费CPU.
        Schedulers.trampoline(); //调度器会将任务按添加顺序依次放入当前线程中等待执行(当前线程就是Schedulers.trampoline调度器创建Worker对象后,Worker对象调用scedule方法所在的线程)。线程一次只执行一个任务,其余任务排队等待,一个任务都执行完成后再开始下一个任务的执行。 
        Schedulers.single(); //拥有一个线程单例,所有的任务都在这一个线程中执行,当此线程中有任务执行时,其他任务将会按照先进先出的顺序依次执行。
        Scheduler.from(@NonNull Executor executor); //指定一个线程调度器,由此调度器来控制任务的执行策略。
        AndroidSchedulers.mainThread(); //在Android UI线程中执行任务,为Android开发定制。
        Observable.subscribeOn(); //指subscribe() 所发生的线程,即Observable.onSubscribe被激活时所处的线程。或者叫做事件产生的线程。
            //若多次设定,则只有一次起作用。
        Observable.observeOn(); //指Subscriber所运行在的线程,或者叫做事件的消费线程。(可以理解为现在要去渲染页面了,需要到主线程中去)
            //若多次设定,每次均起作用。

- 案例1


    基本概念1-4应用
    遍历数组,找出数组中b开头的元素,将其转换为大写
    sample1:fori实现
    public class MainActivity extends AppCompatActivity {

        public static final String TAG = MainActivity.class.getSimpleName();
        String[] arr = {"shanghai", "beijing", "chengdu"};
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            for (int i = 0; i < arr.length ; i++) {
                if (arr[i].startsWith("b")){
                    arr[i] = arr[i].toUpperCase();
                    Log.i(TAG,arr[i]);
                }
            }

        }
    }
    输出结果:06-30 10:48:02.487 747-747/com.kwunyamshan.rxjava I/MainActivity: BEIJING


    sample2:RxJava实现
    public class MainActivity extends AppCompatActivity {

        public static final String TAG = MainActivity.class.getSimpleName();
        String[] arr = {"shanghai", "beijing", "chengdu"};

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //导包不要导错 import io.reactivex.Observable;
            Observable observable = Observable.fromArray(arr);
            //添加一个过滤器 , 把字母b开头的元素过滤出来
            Observable filterObservable = observable.filter(new Predicate() {
                @Override
                public boolean test(String s) throws Exception {
                    return s.startsWith("b");
                }
            });
            //接收结果
            Observer observer = new Observer() {
                @Override
                public void onSubscribe(Disposable d) {}

                //真正处理事件的方法
                @Override
                public void onNext(String s) {
                    s = s.toUpperCase();
                    Log.i(TAG, s);
                }

                @Override
                public void onError(Throwable e) {}

                @Override
                public void onComplete() {}
            };

            //关联观察者与被观察者
            filterObservable.subscribe(observer);
    }
    输出结果:06-30 10:49:00.371 3261-3261/com.kwunyamshan.rxjava I/MainActivity: BEIJING


    sample3:RxJava实现(优化)
    看起来sample1中的代码比sample2中的代码还要简洁,脾气暴躁的大哥就要来干我了,别急一步一步来你就明
        白了,下面是对RXJava进行了优化

    public class MainActivity extends AppCompatActivity {

        public static final String TAG = MainActivity.class.getSimpleName();
        String[] arr = {"shanghai", "beijing", "chengdu"};

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Observable.fromArray(arr)
                    ////filter过滤以后返回的类型也是Observable, 所以变量可以删去,链式编程
                    //Observable filterObservable = observable.filter(new Predicate() {
                    .filter(new Predicate() {
                        @Override
                        public boolean test(String s) throws Exception {
                            return s.startsWith("b");
                        }
                    })
                    //这里如果需要做一件事则不需要new Observer,
                    .subscribe(new Consumer() {
                        @Override
                        public void accept(String s) throws Exception {
                            s = s.toUpperCase();
                            Log.i(TAG, s);
                        }
                    });
    }
    输出结果:06-30 10:51:00.789 3261-3261/com.kwunyamshan.rxjava I/MainActivity: BEIJING
    你会发现这样写逻辑条理会变得特别清楚(如果会用lambda表达式的话则会更加的简洁),一个方法做一件
        事情,再加多少个方法逻辑也不会乱,这样写不管过了多久再回过头来看这段代码是不是也不迷糊了

- 案例2

    基本概念1-5应用
    获取图片,展示到ImageView上,出现异常时打印toast报错(涉及到切换线程)

    sample1:不考虑线程问题,简单实现11数据转换(关键字just)
    public class MainActivity extends AppCompatActivity {

        public static final String TAG = MainActivity.class.getSimpleName();

        private ImageView ivAvatar;
        private int imgId = R.mipmap.avatar;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ivAvatar = findViewById(R.id.iv_avatar);
            //当对象是单个的时候调用just
            Observable.just(imgId)
                    //将图片id转化为drawable
                    .map(new Function() {
                        @Override
                        public Drawable apply(Integer integer) throws Exception {
                            return getResources().getDrawable(imgId);
                        }
                    })
                    //把drawable设置到ImageView上
                    .subscribe(new Consumer() {
                        @Override
                        public void accept(Drawable drawable) throws Exception {
                            ivAvatar.setImageDrawable(drawable);
                        }
                    });
    }


    sample2:增加线程切换,11数据转换(关键字just)不了解线程切换的翻回去看 5. Scheduler
    public class MainActivity extends AppCompatActivity {

        public static final String TAG = MainActivity.class.getSimpleName();

        private ImageView ivAvatar;
        private int imgId = R.mipmap.avatar;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ivAvatar = findViewById(R.id.iv_avatar);
            //当对象是单个的时候调用just
            Observable
                    .just(imgId)

                    //将图片id转化为drawable, 比方这个地方走网络请求图片的话这样肯定是走不成了
                    //所以我们需要在这里添加切换线程的方法
                    .subscribeOn(Schedulers.io())
                    //以下代码在子线程中执行
                    .map(new Function() {
                        @Override
                        public Drawable apply(Integer integer) throws Exception {
                            return getResources().getDrawable(imgId);
                        }
                    })
                    //把drawable设置到ImageView上 , 渲染页面的逻辑在主线程中调用
                    .observeOn(AndroidSchedulers.mainThread())
                    //以下代码在主线程中执行
                    .subscribe(new Observer() {
                        @Override
                        public void onSubscribe(Disposable d) {}

                        @Override
                        public void onNext(Drawable drawable) {
                            ivAvatar.setImageDrawable(drawable);
                        }

                        @Override
                        public void onError(Throwable e) {
                            Toast.makeText(MainActivity.this,e.getMessage(),1).show();
                        }

                        @Override
                        public void onComplete() {}
                    });
        }

- 案例3

     基本概念1-5应用
     现在有两张表,一张单位职工表,一张职工工资表,根据职工姓名(职工表)查询职工每个月的工资(工资表)
     sample1:fori实现1对多查询
    public class MainActivity extends AppCompatActivity {

        public static final String TAG = MainActivity.class.getSimpleName();

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

            SalaryBean jan = new SalaryBean("3000", 8);
            SalaryBean feb = new SalaryBean("3400", 9);
            SalaryBean mar = new SalaryBean("3000", 10);
            SalaryBean apr = new SalaryBean("3400", 11);
            SalaryBean may = new SalaryBean("5500", 12);

            List salaryList = new ArrayList<>();
            salaryList.add(jan);
            salaryList.add(feb);
            salaryList.add(mar);
            salaryList.add(apr);
            salaryList.add(may);
            StaffBean 秃头李 = new StaffBean("李老板", salaryList);

            for (int i = 0; i < 秃头李.getmSalaryList().size(); i++) {
                SalaryBean salaryBean = 秃头李.getmSalaryList().get(i);
                Log.i(TAG, "您" + salaryBean.getMonth() + "月份" + "的薪水:" + salaryBean.getSalary());
            }
        }
    }
    输出结果:
    06-30 10:53:48.641 8985-8985/com.kwunyamshan.rxjava I/MainActivity: 您8月份的薪水:3000
    06-30 10:53:48.641 8985-8985/com.kwunyamshan.rxjava I/MainActivity: 您9月份的薪水:3400
    06-30 10:53:48.641 8985-8985/com.kwunyamshan.rxjava I/MainActivity: 您10月份的薪水:3000
    06-30 10:53:48.641 8985-8985/com.kwunyamshan.rxjava I/MainActivity: 您11月份的薪水:3400
    06-30 10:53:48.642 8985-8985/com.kwunyamshan.rxjava I/MainActivity: 您12月份的薪水:5500



    sample2:用RxJava实现1对多查询(关键字flatMap)
    public class MainActivity extends AppCompatActivity {

        public static final String TAG = MainActivity.class.getSimpleName();

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            SalaryBean jan = new SalaryBean("3000", 8);
            SalaryBean feb = new SalaryBean("3400", 9);
            SalaryBean mar = new SalaryBean("3000", 10);
            SalaryBean apr = new SalaryBean("3400", 11);
            SalaryBean may = new SalaryBean("5500", 12);

            List salaryList = new ArrayList<>();
            salaryList.add(jan);
            salaryList.add(feb);
            salaryList.add(mar);
            salaryList.add(apr);
            salaryList.add(may);
            StaffBean 秃头李 = new StaffBean("李老板", salaryList);

            //查询单个的员工用just
            Observable
                    .just(秃头李)
                    //查询员工每个月工资情况用flatMap
                    .flatMap(new Function>() {
                        @Override
                        public Observable apply(StaffBean staffBean) throws Exception {
                            return Observable.fromIterable(staffBean.getmSalaryList());

                        }
                    })
                    .subscribe(new Consumer() {
                        @Override
                        public void accept(SalaryBean salaryBeans) throws Exception {

                            Log.i(TAG,  "您" + salaryBeans.getMonth() + "月份" + "的薪水:" + salaryBeans.getSalary());
                        }
                    });

        }
    输出结果:
    06-30 10:54:16.278 10183-10183/com.kwunyamshan.rxjava I/MainActivity: 您8月份的薪水:3000
    06-30 10:54:16.278 10183-10183/com.kwunyamshan.rxjava I/MainActivity: 您9月份的薪水:3400
    06-30 10:54:16.278 10183-10183/com.kwunyamshan.rxjava I/MainActivity: 您10月份的薪水:3000
    06-30 10:54:16.278 10183-10183/com.kwunyamshan.rxjava I/MainActivity: 您11月份的薪水:3400
    06-30 10:54:16.278 10183-10183/com.kwunyamshan.rxjava I/MainActivity: 您12月份的薪水:5500

案例下载传送门

你可能感兴趣的:(ADT)