RxJava使用场景

本文主要是讲RxJava的使用,没有分析其原理。

为什么学习RxJava?

改变思维来提升效率

RxJava是响应式编程的思想

响应式编程即一系列操作是连续的,是流水线,从起点流到终点不会断的,比如:请求下载图片 -> 获取返回的结果 -> 更新UI,这整个的请求和响应的代码可以写在一行代码中(即只有一个代表语句结束的分号“;”)。

响应式编程的思想最早是微软架构组提出的。

Rx思维: 响应式编程

生活中的例子:
起点(分发事件(PATH):我饿了)----------下楼-------去餐厅--------点餐----------> 终点(吃饭 消费事件)

程序中的例子:
起点(分发事件:点击登录)----------登录API-------请求服务器--------获取响应码----------> 终点(更新UI登录成功 消费事件)

学习经典架构

Github:https://github.com/ReactiveX/RxJava
Author:JakeWharton 被誉为Android之神
Star:42K

Rx系列

官网:http://reactivex.io/#

Rx即响应式编程,很多语言都有对应的Rx框架
在这里插入图片描述

RxJava操作符应用

在这里插入图片描述
RxJava的操作符非常多,不需要每一个都学,只需要学习大部分操作符的通用的内容,通过学习两个操作符即可。

学习资料

注意:RxJava入门与基础的内容 已梳理好了(此内容不讲)
在这里插入图片描述

入门相关的资料与博客:
https://www.jianshu.com/p/cd3557b1a474
https://www.cnblogs.com/lyysz/p/6344507.html
https://www.cnblogs.com/liushilin/p/7058302.html
https://www.jb51.net/article/92309.htm
https://zhuanlan.zhihu.com/p/31413825

基础相关的资料与博客:
https://github.com/ReactiveX/RxJava
/给学生的资料/RxJava全套使用完整版.md
/给学生的资料/RxJava操作符大全.xmind 同学们可以结合“RxJava操作符大全”
去网上查询具体操作符的使用(这是学习方法)

RxJava2.0 与 RxJava3.0 差异化:
https://blog.csdn.net/weixin_45258969/article/details/95386872

RxJava 整个课程的安排

注意:RxJava 整个课程的安排(说明难度曲线)第一节课
在这里插入图片描述

第一次课目录

在这里插入图片描述

  • 核心思想
  • RxJava配合Retrofit
  • 防抖
  • 网络嵌套
  • doOnNext运用

第一节课难度曲线:
在这里插入图片描述

RxJava核心思想

在这里插入图片描述
整个事件的流向过程中,下一层的类型根据上一层的类型进行变化。比如上一层流出的是String,那么下一层的接收的类型也是String

RxJava的三要素:

  • 起点
  • 事件
  • 终点,事件从起点流向终点

传统的思维方式下载图片

注意:传统方式 来完成 “下载图片功能“,每一位开发者的思路都不同,就是传统的编程思维

	// TODO 传统方式
    // 传统方式: 思维无法固定,不同的人有不同的编程思维 (后面接手你写的项目,看不懂)
    // A程序员:35356453 自己的思维 不同  封装方法....
    // B程序员:46576576 自己的思维 不同  全部写在一起
    // C程序员:43643654 自己的思维 不同  new Thread
    // D程序员:66545655 自己的思维 不同  使用 线程池
    // ...
    // 零零散散,麻烦,  每个写代码的人的思维都不一样
    public void downloadImageAction(View view) {
        progressDialog = new ProgressDialog(this);
        progressDialog.setTitle("下载图片中...");
        progressDialog.show();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    URL url = new URL(PATH);
                    HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
                    httpURLConnection.setConnectTimeout(5000);
                    int responseCode = httpURLConnection.getResponseCode(); // 才开始 request
                    if (responseCode == HttpURLConnection.HTTP_OK) {
                        InputStream inputStream = httpURLConnection.getInputStream();
                        Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                        Message message = handler.obtainMessage();
                        message.obj = bitmap;
                        handler.sendMessage(message);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

RxJava的思维方式下载图片

map示意图:
在这里插入图片描述

    /**
     * RxJava思想思维编程:事件从起点流到终点,起点是被观察者,终点是观察者
     * 中间可以通过map操作符插入一些功能
     *
     * @param view
     */
    public void rxJavaDownloadImageAction(View view) {
        // 起点
        Observable.just(PATH)  // 内部会分发  PATH Stirng  // TODO 第二步

                .map(new Function<String, Bitmap>() {    // TODO 第三步
                    @Override
                    public Bitmap apply(String s) throws Exception {
                        URL url = new URL(PATH);
                        HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
                        httpURLConnection.setConnectTimeout(5000);
                        int responseCode = httpURLConnection.getResponseCode(); // 才开始 request
                        if (responseCode == HttpURLConnection.HTTP_OK) {
                            InputStream inputStream = httpURLConnection.getInputStream();
                            Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                            return bitmap;
                        }
                        return null;
                    }
                })
                /*
                    //如果不需要这部分功能,只需要把这块代码注释掉即可
                    .map(new Function<Bitmap, Bitmap>() {
                    @Override
                    public Bitmap apply(Bitmap bitmap) throws Exception {
                        Paint paint = new Paint();
                        paint.setTextSize(88);
                        paint.setColor(Color.RED);
                        return drawTextToBitmap(bitmap, "同学们大家好",paint, 88 , 88);
                    }
                })*/

                // 日志记录
                .map(new Function<Bitmap, Bitmap>() {
                    @Override
                    public Bitmap apply(Bitmap bitmap) throws Exception {
                        Log.d(TAG, "apply: 是这个时候下载了图片啊:" + System.currentTimeMillis());
                        return bitmap;
                    }
                })

                /*
                .subscribeOn(Schedulers.io())     // 给上面代码分配异步线程
                .observeOn(AndroidSchedulers.mainThread()) // 给下面代码分配主线程;
                */

                //  .compose(rxud()) 对上面的
                //  .subscribeOn(Schedulers.io())
                // .observeOn(AndroidSchedulers.mainThread())
                // 进行封装
                .compose(rxud())

                // 订阅:将 起点 和 终点 订阅起来
                .subscribe(

                        // 终点
                        new Observer<Bitmap>() {

                            // 订阅开始
                            @Override
                            public void onSubscribe(Disposable d) {
                                // 预备 开始 要分发
                                // TODO 第一步
                                progressDialog = new ProgressDialog(DownloadActivity.this);
                                progressDialog.setTitle("download run");
                                progressDialog.show();
                            }

                            // TODO 第四步
                            // 拿到事件
                            @Override
                            public void onNext(Bitmap bitmap) {
                                image.setImageBitmap(bitmap);
                            }

                            // 错误事件
                            @Override
                            public void onError(Throwable e) {

                            }

                            // TODO 第五步
                            // 完成事件
                            @Override
                            public void onComplete() {
                                if (progressDialog != null)
                                    progressDialog.dismiss();
                            }
                        }
                );

    }

RxJava配合Retrofit

Retrofit是对请求进行封装,然后交给okhttp执行真正的网络请求,再将响应结果交给RxJava。

  • Retrofit处理请求出去的数据
  • okhttp执行真正的网路请求
  • RxJava处理响应回来的数据

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

public interface WangAndroidApi {

    // 总数据
    @GET("project/tree/json")
    Observable<ProjectBean> getProject();  // 异步线程 耗时操作, Observable是起点,ProjectBean是事件

    // Item数据
    @GET("project/list/{pageIndex}/json") // ?cid=294
    Observable<ProjectItem> getProjectItem(@Path("pageIndex") int pageIndex, @Query("cid") int cid);  // 异步线程 耗时操作
}

	
	private WangAndroidApi api;


    /**
     * TODO Retrofit+RxJava 查询 项目分类  (总数据查询)
     *
     * @param view
     */
    public void getProjectAction(View view) {
        // 获取网络API
        api.getProject()
                .subscribeOn(Schedulers.io()) // 上面 异步
                .observeOn(AndroidSchedulers.mainThread()) // 下面 主线程
                .subscribe(new Consumer<ProjectBean>() {
                    @Override
                    public void accept(ProjectBean projectBean) throws Exception {
                        Log.d(TAG, "accept: " + projectBean); // UI 可以做事情
                    }
                });

    }

View防抖

同一个View点了5次,只会执行1次操作。

在这里插入图片描述

网络嵌套

在这里插入图片描述
如何避免网络嵌套?如何做到不嵌套也能查询出这两层数据?使用flatMap操作符。

flatMap示意图:
在这里插入图片描述

flatMap的作用:可以对输入的数据产生多个输出。

起点可以分发一个数据,通过flatMap 产生多个输出。
onNext(1);
|
|
|
flatMap :自己分发 10个数据 给下面
1 --> 多发送 10次 1+“DDD”
|
|
|
subscribe{
1+“DDD”
1+“DDD”
1+“DDD”
1+“DDD”
1+“DDD”
1+“DDD”
1+“DDD”
1+“DDD”
1+“DDD”
1+“DDD”
}


    /**
     * RxJava
     * RxJs
     * Rxxxxx
     * RxBinding  防抖
     * <p>
     * TODO 功能防抖 + 网络嵌套(这种是负面教程,嵌套的太厉害了)
     * 2层嵌套
     * 6层
     */
    @SuppressLint("CheckResult")
    private void antiShakeActon() {
        // 注意:(项目分类)查询的id,通过此id再去查询(项目列表数据)

        // 对那个控件防抖动?
        Button btn_anti_shake = findViewById(R.id.bt_anti_shake);

        RxView.clicks(btn_anti_shake)
                .throttleFirst(2000, TimeUnit.MILLISECONDS) // 2秒钟之内 响应你一次
                .subscribe(new Consumer<Object>() {
                    @Override
                    public void accept(Object o) throws Exception {
                        api.getProject() // 查询主数据
                                .compose(DownloadActivity.rxud())
                                .subscribe(new Consumer<ProjectBean>() {
                                    @Override
                                    public void accept(ProjectBean projectBean) throws Exception {
                                        //通过遍历主数据查询item数据
                                        for (ProjectBean.DataBean dataBean : projectBean.getData()) { // 10
                                            // 查询item数据
                                            api.getProjectItem(1, dataBean.getId())
                                                    .compose(DownloadActivity.rxud())
                                                    .subscribe(new Consumer<ProjectItem>() {
                                                        @Override
                                                        public void accept(ProjectItem projectItem) throws Exception {
                                                            Log.d(TAG, "accept: " + projectItem); // 可以UI操作
                                                        }
                                                    });
                                        }
                                    }
                                });
                    }
                });
    }

    /**
     * TODO 功能防抖 + 避免网络嵌套 (解决嵌套的问题):使用 flatMap 操作符
     */
    @SuppressLint("CheckResult")
    private void antiShakeActonUpdate() {
        // 注意:项目分类查询的id,通过此id再去查询(项目列表数据)

        // 对那个控件防抖动?
        Button btn_anti_shake = findViewById(R.id.bt_anti_shake);

        RxView.clicks(btn_anti_shake)
                .throttleFirst(2000, TimeUnit.MILLISECONDS) // 2秒钟之内 响应你一次

                // 我只给下面切换异步线程, 上面的throttleFirst是运行在主线程
                .observeOn(Schedulers.io())
                .flatMap(new Function<Object, ObservableSource<ProjectBean>>() {//是通过ObservableSource实现多个输出的
                    @Override
                    public ObservableSource<ProjectBean> apply(Object o) throws Exception {
                        return api.getProject(); // 主数据
                    }
                })

                // 第一步不能使用map,因为 api 返回的是 Observbale<ProjectBean>,可以尝试下是否可以
                /*
                .map(new Function<Object, ObservableSource<ProjectBean>>() {
                    @Override
                    public ObservableSource<ProjectBean> apply(Object o) throws Exception {
                        return api.getProject(); // 主数据;
                    }
                })
                */

                .flatMap(new Function<ProjectBean, ObservableSource<ProjectBean.DataBean>>() {
                    @Override
                    public ObservableSource<ProjectBean.DataBean> apply(ProjectBean projectBean) throws Exception {
                        //Observable.fromIterable会遍历projectBean.getData()的数据,有几个数据就发几次
                        return Observable.fromIterable(projectBean.getData()); // 我自己创建一个发射器 发多次
                    }
                })
                .flatMap(new Function<ProjectBean.DataBean, ObservableSource<ProjectItem>>() {
                    @Override
                    public ObservableSource<ProjectItem> apply(ProjectBean.DataBean dataBean) throws Exception {
                        return api.getProjectItem(1, dataBean.getId());
                    }
                })

                .observeOn(AndroidSchedulers.mainThread()) // 给下面切换到主线程
                .subscribe(new Consumer<ProjectItem>() {
                    @Override
                    public void accept(ProjectItem projectItem) throws Exception {
                        // 如果我要更新UI
                        Log.d(TAG, "accept: " + projectItem);
                    }
                });
    }

doOnNext运用

使用场景:一个需求涉及到很多个接口,一个接口返回结果后才能进行下一个接口对应的操作。

doOnNext运用 (一行代码完成此需求)
在这里插入图片描述

RxJava的内存泄漏

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 必须这样写,最起码的标准
        if (disposable != null)
            if (!disposable.isDisposed())
                disposable.dispose();
    }

要在activity的onDestroy()中进行dispose()。

原因:

在这里插入图片描述
如果网络请求过程中比较慢,此时用户退出了页面,那么要进行dispose(),因为RxJava在分发事件的时候会根据isDisposed判断是否要中断分发,如果不进行dispose(),那么退出页面后RxJava会继续分发事件流,会继续执行后续的操作,而此时已经退出页面了,后续操作是不需要执行的,因此退出页面时需要调用dispose()。

作业

说说RxJava的核心思想的自己的理解?
有一个起点和一个终点,起点开始流向我们的“事件”,把事件流向到终点,只不过在流向的过程中,可以增加拦截,拦截时可以对“事件进行改变”,终点只关心它上一个拦截,与其他的无关。

JAVA设计模式之观察者模式

1、初步认识

观察者模式的定义:

在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。

大白话:

其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。

2、这个模式的结构图

3、可以看到,该模式包含四个角色

  • 抽象被观察者角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
  • 抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
  • 具体被观察者角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。
  • 具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。

4、使用场景例子

有一个微信公众号服务,不定时发布一些消息,关注公众号就可以收到推送消息,取消关注就收不到推送消息。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页