RX基本思想

402 阅读4分钟

RX基本思想

rx 本质上来讲不是基于某一种语言的库,而是一种思想。想要搞懂Rx 那么必须要明白它的思想。

其实就是 起点到终点的一系列的事件流,举个例子来说,我们的饮用水,起点是水库的地下水,终点是我们家的水龙头,中间我们可以做很多操作,比如 我们可以净化水等等。。。。 但是无论怎样中间的水流是不会断的, 也就是这个事件是连续的。

再比如我们程序中 点击登陆(起点)---->请求登陆API---->获取响应信息---->登陆成功(终点) 这一系列的事件流就可以用Rx来表示

基本使用

网络请求中最常用的就是Retrofit+RxJava

  1. 首先定义APiService
public interface APiService {

    // 总数据
    @GET("project/tree/json")
    Observable<ProjectBean> getProject();

    // item数据
    @GET("project/list/{pageIndex}/json") 
    Observable<ProjectItem> getProjectItem(@Path("pageIndex") int  pageIndex, 
                                           @Query("cid") int cid);
    
}

其实也就是正常的Retrofit使用流程 只不过 把返回类型变成 Observable<T>了 表示起点是这里了

2.请求数据

       // 获取网络API
        api.getProject()
                .subscribeOn(Schedulers.io()) // 上面 异步
                .observeOn(AndroidSchedulers.mainThread()) // 下面 主线程
                .subscribe(new Observer<ProjectBean>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        
                    }

                    @Override
                    public void onNext(ProjectBean projectBean) {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });

第一行不用说,就是Retrofit的用法 获取起点 , 那么终点呢?终点自然就是 new Observer <ProjectBean>(){}了 ,起点和终点之间需要和subscribe来连接起来了。 那么中间第二行和第三行干什么呢? 第二行表示上面的是运行在IO线程的(网络请求),下面的是运行在主线程里的。基本使用就这么简单。当然 ,还有简化版的

 api.getProject()
                .subscribeOn(Schedulers.io()) // 上面 异步
                .observeOn(AndroidSchedulers.mainThread()) // 下面 主线程
                .subscribe(new Consumer<ProjectBean>() {
                    @Override
                    public void accept(ProjectBean projectBean) throws Exception {
                        
                    }
                });

当然还可以使用lambda表达式

 api.getProject()
                .subscribeOn(Schedulers.io()) // 上面 异步
                .observeOn(AndroidSchedulers.mainThread()) // 下面 主线程
                .subscribe(v->{
                    
                });

上面三种都是一样的结果的,需要注意的是 lambda表达是使用起来很简洁,但是可读性较差,根据需要使用。

  1. 再举个例子,比如说我们从网络上下载图片 转换成bitmap显示出来
       // 起点
        Observable.just(PATH) 
        .map(new Function<String, Bitmap>() {
            @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(); 
                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())
        // 订阅 起点 和 终点 订阅起来
        .subscribe(
                // 终点
                new Observer<Bitmap>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        progressDialog = new ProgressDialog(DownloadActivity.this);
                        progressDialog.setTitle("download run");
                        progressDialog.show();
                    }

                    @Override
                    public void onNext(Bitmap bitmap) {
                        image.setImageBitmap(bitmap);
                    }

                    @Override
                    public void onError(Throwable e) {

                    }
                    @Override
                    public void onComplete() {
                        if (progressDialog != null)
                            progressDialog.dismiss();
                    }
        });

可以看到 我们在起点和终点之间添加删除任何功能都很简单 ,只需要添加对应的map就行。这在传统思想的编程里是做不到的。

功能防抖

什么叫功能防抖呢?比如一个按钮,正常情况下,在一秒时间内我不停的点击 ,它就会响应N次,这就是抖动了 ,显然像这种不合理的用户操作我们应该屏蔽掉。这就需要用到RxBinding的功能了,代码如下:

         RxView.clicks(btnView)
                // 1秒钟之内 只会响应一次
                .throttleFirst(1000,TimeUnit.MILLISECONDS)
                .subscribe(new Consumer<Object>() {
                    @Override
                    public void accept(Object o) throws Exception {
                        
                    }
                });

网络嵌套

假设有这样的一个需求,点击按钮,查询主数据里的全部item的详细数据,那么,正常的思路就是 先查主数据,成功之后再根据每个Id 查询 item里的数据,这里就会有网络嵌套。之前代码如下:

 RxView.clicks(btnView)
                .throttleFirst(1000, TimeUnit.MILLISECONDS) 
                .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 {
                                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操作
                                        }
                                    });
                                }
                            }
                        });
                    }
                });

代码很难看,如果再多来几层嵌套 维护成本就很大。Rx的思想是事件流的形式的 ,完全可以解决这个问题,看Rx解决的代码:

RxView.clicks(btnView)
               .throttleFirst(1000,TimeUnit.MILLISECONDS)
               .observeOn(Schedulers.io())
               .flatMap(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 {
                       //自己定义一个发射器 可以发射N个 一个一个的发射,相当于 for循环
                       return Observable.fromIterable(projectBean.getData());
                   }
               })
               .flatMap(new Function<ProjectBean.DataBean, ObservableSource<ProjectItem>>() {
                   @Override
                   public ObservableSource<ProjectItem> apply(ProjectBean.DataBean dataBean) throws Exception {
                       //请求item的数据
                       return api.getProjectItem(1,dataBean.getId());
                   }
               })
              //切回主线程(更新UI)
               .observeOn(AndroidSchedulers.mainThread())
               .subscribe(new Consumer<ProjectItem>() {
                   @Override
                   public void accept(ProjectItem projectItem) throws Exception {
                       
                   }
               });

可以看到代码优雅多了。