Android中的Rx思维

247 阅读6分钟
最近在学习Android Studio的过程中,发现了一种RxJava的开发思路,通过一番搜索,了解了Rx思维的妙处

什么是Rx思维

提升开发效率,降低维护成本一直是开发团队永恒不变的宗旨。近一年来国内的技术圈子中越来越多的开始提及Rx。它能帮助我们简化代码逻辑,提升代码可读性。这对于开发效率的提升、后期维护成本的降低帮助都是巨大的。

响应式编程

Rx思维,就是响应式编程思维,什么是响应式编程?响应式编程是一种基于异步数据流概念的编程模式。数据流就像一条河:它可以被观测,被过滤,被操作,或者为新的消费者与另外一条流合并为一条新的流。

响应式编程的一个关键概念是事件。事件可以被等待,可以触发过程,也可以触发其它事件。事件是唯一的以合适的方式将我们的现实世界映射到我们的软件中:如果屋里太热了我们就打开一扇窗户。同样的,当我们的天气app从服务端获取到新的天气数据后,我们需要更新app上展示天气信息的UI;汽车上的车道偏移系统探测到车辆偏移了正常路线就会提醒驾驶者纠正,就是是响应事件。

简单来说,Rx编程就是一种链条式编程,在程序中定义起点与终点,起点与终点之间有一条链条,程序中的所有功能都在链条中实现,且这种实现式逐步的,先完成的功能会影响到之后功能的实现,用一句话总结就是:根据上一层的响应,影响下一层的变化。

一般开发与Rx思维开发的区别

在一般的项目开发中,都是多人同时开发一个项目,每个人负责不同的板块,然而,不同人的思维是不一样的,即使开发的是同一个项目,也会有不同的方法。举个例子,如果要开发一个功能,点击按钮可以下载一张图片,并在图片上添加一个水印,如果我们采用传统方式来完成此功能,每位开发者的思想都不一样 (思维不同 ) 比如A会使用线程池,B会使用Thread + Handler方法,C会使用其他更加古老的方法如果采用传统开发方式,我们后面的开发者接手前面开发者的代码,就很痛苦,这便是传统开发方法的弊端,而使用Rx思维来开发,就方便很多。

首先要定义起点和终点

  // 起点
    Observable.just(PATH)
            //关联:观察者模式
            .subscribe(
                    //终点
                    new Observer<Bitmap>() {
                @Override
                public void onSubscribe(Disposable d) {
                }
                @Override
                public void onNext(Bitmap bitmap) {
                }

                @Override
                public void onError(Throwable e) {
                }

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

这里采用的操作符为just()(在RxJava中,所有的函数都被称为操作符,因为函数要去操作从起点流向终点),即将传送的数据以此发送出去,最多可传递10个参数,且要求是将原为String类型的path转换为Bitmap类型

下载图片需求

使用map()方法,下载图片的同时将String类型转换为Bitmap类型

Observable.just(PATH)
        //图片下载需求  PATH ---》 Bitmap
        .map(new Function<String, Bitmap>() {
            @Override
            public Bitmap apply(String path) throws Exception {

                try {

                    URL url = new URL(path);
                    HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
                    httpURLConnection.setConnectTimeout(5000); // 设置请求连接时长 5秒
                    int responseCode = httpURLConnection.getResponseCode(); // 才开始 request    拿到服务器的响应  200成功  404有问题 ...
                    if (responseCode == HttpURLConnection.HTTP_OK) {
                        InputStream inputStream = httpURLConnection.getInputStream();
                        Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                        return bitmap;
                    }

                }catch (Exception e){
                    e.printStackTrace();
                }
                return null;
            }
        })

在起点just(PATH)与终点new Observer<Bitmap>()之间添加map()方法并在里面写入具体实现

添加水印需求

依旧采用map()方法,将上一次提供的数据经过改动传递下去

.map(new Function<Bitmap, Bitmap>() {
    @NonNull
    @Override
    public Bitmap apply(@NonNull Bitmap bitmap) throws Exception {
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setTextSize(88);
        Bitmap shuiyingBitmap = drawTextToBitmap(bitmap, "@Mirae DNG", paint, 88, 88);
        return shuiyingBitmap;
    }
})

这里提供一种添加水印的函数方法drawTextToBitmap

private final Bitmap drawTextToBitmap(Bitmap bitmap, String text, Paint paint, int paddingLeft, int paddingTop) {
    Bitmap.Config bitmapConfig = bitmap.getConfig();

    paint.setDither(true); // 获取跟清晰的图像采样
    paint.setFilterBitmap(true);// 过滤一些
    if (bitmapConfig == null) {
        bitmapConfig = Bitmap.Config.ARGB_8888;
    }
    bitmap = bitmap.copy(bitmapConfig, true);
    Canvas canvas = new Canvas(bitmap);

    canvas.drawText(text, paddingLeft, paddingTop, paint);
    return bitmap;
}

由于Rx编程是链条式的,其在添加或修改功能时十分方便,只需在起点和终点之间寻找合适的位置,将要添加的功能写入就可以了,相反,如果要删除某些功能,只需在链条中找到要删除的功能,将其注释就好,简单快捷。

完善代码

下面给出完整代码

// 打印logcat日志的标签
private final String TAG = MainActivity.class.getSimpleName();

// 网络图片的链接地址
private final static String PATH = "xxx";//这里填写要下载的图片地址

// 弹出加载框(正在加载中...)
private ProgressDialog progressDialog;

// ImageView控件,用来显示结果图像
private ImageView image;
Observable.just(PATH)

        // TODO 第三步
        // 需求:001 图片下载需求  PATH ---》 Bitmap
        .map(new Function<String, Bitmap>() {
            @Override
            public Bitmap apply(String path) throws Exception {

                try {
                    Thread.sleep(2000); // 睡眠2秒钟

                    URL url = new URL(path);
                    HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
                    httpURLConnection.setConnectTimeout(5000); // 设置请求连接时长 5秒
                    int responseCode = httpURLConnection.getResponseCode(); // 才开始 request    拿到服务器的响应  200成功  404有问题 ...
                    if (responseCode == HttpURLConnection.HTTP_OK) {
                        InputStream inputStream = httpURLConnection.getInputStream();
                        Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                        return bitmap;
                    }

                }catch (Exception e){
                    e.printStackTrace();
                }
                return null;
            }
        })

        // 需求:002 加水印
        .map(new Function<Bitmap, Bitmap>() {
            @NonNull
            @Override
            public Bitmap apply(@NonNull Bitmap bitmap) throws Exception {
                Paint paint = new Paint();
                paint.setColor(Color.RED);
                paint.setTextSize(88);
                Bitmap shuiyingBitmap = drawTextToBitmap(bitmap, "@Mirae DNG", paint, 88, 88);
                return shuiyingBitmap;
            }
        })

        // 需求:003 日志记录需求
        .map(new Function<Bitmap, Bitmap>() {
            @NonNull
            @Override
            public Bitmap apply(@NonNull Bitmap bitmap) throws Exception {
                Log.e(TAG, "什么时候下载了图片 apply: " + System.currentTimeMillis() );
                return bitmap;
            }
        })

        // 给上面的分配异步线程(图片下载操作)
        .subscribeOn(Schedulers.io())

        // 终点分配 Android主线程
        .observeOn(AndroidSchedulers.mainThread())

        //关联:观察者模式
        .subscribe(
                //终点
                new Observer<Bitmap>() {

            // TODO 第一步
            // 订阅成功
            @Override
            public void onSubscribe(Disposable d) {
                // 显示加载框
                progressDialog = new ProgressDialog(MainActivity.this);
                progressDialog.setTitle("RXJava Derry run 正在加载中..");
                progressDialog.show();
            }

            // TODO 第四步 显示图片   水印的Bitmap
            // 上一层给我的响应
            @Override
            public void onNext(Bitmap bitmap) {
                image.setImageBitmap(bitmap);//显示到控件
            }

            // 链条思维发生了异常
            @Override
            public void onError(Throwable e) {

            }

            // TODO 第五步 整个链条思维全部结束
            // 整个链条全部结束
            @Override
            public void onComplete() {

            }
        });

Rx思维总结

Rx思维开发为后来者读懂,修改前人的代码提供了相当大的便利。Android平台上为已经开发者提供了AsyncTask,Handler等用来做异步操作的类库,那我们为什么还要选择RxJava呢?答案是简洁!RxJava可以用非常简洁的代码逻辑来解决复杂问题;而且即使业务逻辑的越来越复杂,它依然能够保持简洁!再配合上Lambda用简单的几行代码分分钟就解决你负责的业务问题。