RxJava基本使用

RxJava基本使用

Rx介绍

ReactiveX的历史

ReactiveX是Reactive Extensions的缩写,一般简写为Rx,最初是LINQ的一个扩展,由微软的架构师Erik Meijer领导的团队开发,在2012年11月开源,Rx是一个编程模型,目标是提供一致的编程接口,帮助开发者更方便的处理异步数据流,Rx库支持.NET、JavaScript和C++,Rx近几年越来越流行了,现在已经支持几乎全部的流行编程语言了,Rx的大部分语言库由ReactiveX这个组织负责维护,比较流行的有RxJava/RxJS/Rx.NET,社区网站是 reactivex.io

什么是ReactiveX

微软给的定义是,Rx是一个函数库,让开发者可以利用可观察序列和LINQ风格查询操作符来编写异步和基于事件的程序,使用Rx,开发者可以用Observables表示异步数据流,用LINQ操作符查询异步数据流, 用Schedulers参数化异步数据流的并发处理,Rx可以这样定义:Rx = Observables + LINQ + Schedulers。

ReactiveX.io给的定义是,Rx是一个使用可观察数据流进行异步编程的编程接口,ReactiveX结合了观察者模式、迭代器模式和函数式编程的精华。

Rx模式

使用观察者模式
  • 创建:Rx可以方便的创建事件流和数据流
  • 组合:Rx使用查询式的操作符组合和变换数据流
  • 监听:Rx可以订阅任何可观察的数据流并执行操作
简化代码
  • 函数式风格:对可观察数据流使用无副作用的输入输出函数,避免了程序里错综复杂的状态
  • 简化代码:Rx的操作符通通常可以将复杂的难题简化为很少的几行代码
  • 异步错误处理:传统的try/catch没办法处理异步计算,Rx提供了合适的错误处理机制
  • 轻松使用并发:Rx的Observables和Schedulers让开发者可以摆脱底层的线程同步和各种并发问题
使用Observable的优势

Rx扩展了观察者模式用于支持数据和事件序列,添加了一些操作符,它让你可以声明式的组合这些序列,而无需关注底层的实现:如线程、同步、线程安全、并发数据结构和非阻塞IO。

Observable通过使用最佳的方式访问异步数据序列填补了这个间隙

单个数据多个数据
同步T getData()Iterable<T> getData()
异步Future<T> getData()Observable<T> getData()

Rx的Observable模型让你可以像使用集合数据一样操作异步事件流,对异步事件流使用各种简单、可组合的操作。

名词定义

  • Reactive 直译为反应性的,有活性的,根据上下文一般翻译为反应式、响应式
  • Iterable 可迭代对象,支持以迭代器的形式遍历,许多语言中都存在这个概念
  • Observable 可观察对象,在Rx中定义为更强大的Iterable,在观察者模式中是被观察的对象,一旦数据产生或发生变化,会通过某种方式通知观察者或订阅者
  • Observer 观察者对象,监听Observable发射的数据并做出响应,Subscriber是它的一个特殊实现
  • emit 直译为发射,发布,发出,含义是Observable在数据产生或变化时发送通知给Observer,调用Observer对应的方法,文章里一律译为发射
  • items 直译为项目,条目,在Rx里是指Observable发射的数据项,文章里一律译为数据,数据项

RxJava

在RxJava中,一个实现了Observer接口的对象可以订阅(subscribe)一个Observable 类的实例。订阅者(subscriber)对Observable发射(emit)的任何数据或数据序列作出响应。这种模式简化了并发操作,因为它不需要阻塞等待Observable发射数据,而是创建了一个处于待命状态的观察者哨兵,哨兵在未来某个时刻响应Observable的通知。

简单使用

下载图片
//起点
Observable.just(PSTH) // 内部会分发  PATH Stirng  // TODO 第二步
    // TODO 第三步
    .map(new Function<String,Bitmap>(){
        @Overridre
        public Bitmap apply(String s) throws Exception{
            return getBitmap();
        }
    })
    // TODO 第四步
    //添加水印
    .map(new Function<Bitmap,Bitmap>()){
    	@Override
    	public Bitmap apply(Bitmap bitmap) throws Exception{
            return getWatermarkedBitmap(bitmap);
        }
	})
    // TODO 第五步
     // 日志记录
    .map(new Function<Bitmap, Bitmap>() {
         @Override
         public Bitmap apply(Bitmap bitmap) throws Exception {
         	Log.d(TAG, "apply: 是这个时候下载了图片啊:" + System.currentTimeMillis());
            return bitmap;
         }
    })
    .compose(rxud())
    // 订阅 起点 和 终点 订阅起来
    .subscribe(
    	// 终点
    	new Observer<Bitmap>(){
            // 订阅开始
            @Override
            public void onSubscribe(Disposable d){
                // 预备 开始 要分发
               	// TODO 第一步
                progressDialog = new ProgressDialog(context);
                progressDialog.setTitle("download run");
                progressDialog.show();
            }
             // TODO 第六步
             // 拿到事件
            @Override
            public void onNext(Bitmap bitmap){
                image.setImageBitmap(bitmap);
            }
            // 错误事件
            @Override
            public void onError(Throwable e){
                
            }
            // TODO 第七步
            // 完成事件
			@Orerride
            public void onComplete(){
                if (progressDialog != null)
                   progressDialog.dismiss();
            }
        }
	);

private Bitmap getBitmap() throws IOException{
    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;
}

private Bitmap getWatermarkedBitmap(Bitmap bitmap){
    Paint paint = new Paint();
    paint.setTextSize(18);
    paint.setColor(Color.RED);
    return drawTextToBitmap(bitmap,"hello word!!!",paint,88 ,88);
}
private 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;
}
RxJava配合Retrofit
//定义接口API
public interface TestApi{
    @GET("project/tree/json")
    Observable<ProjectBean> getProject();
    @GET("Project/list/{pageIndex}/json")
    Observable<ProjectItem> getProjectItem(@Path("pageIndex") int pageIndex,@Query("cid") int cid);
}

public class HttpUtil{
    private static String BASE_URL="https://www.wanandroid.com/";
    public static void setBaseUrl(String baseUrl){
        BASE_URL=baseUrl;
    }
    public static Retrofit getOnlineRetrofit(){
        OKHttpClient.Builder httpBuilder=new OKHttpClient.Builder();
        OKHttpClient okHttpClient = httpBuilder
            					.addNetworkInterceptor(new StethoInterceptor())
            					.readTimeout(10000,TimeUnit.SECONDS)
            					.connectTimeout(10000,TimeUnit.SECONDS)
            					.writeTimeout(10000,TimeUnit.SECONTS)
            					.build();
        return new Retrofit.Builder().baseUrl(BASE_URL)
            	.client(okHttpClient)
              						// 添加一个json解析的工具
            	.addConverterFactory(GsonConverterFactory.create(new Gson()))
            	// 添加rxjava处理工具			
            	.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            	.build();
    }
}

public void getProgectAction(View view){
    TestApi testApi = HttpUtil.getOnLineRetrofit().create(TestApi.class);
    testApi.getProject()
        .subscribeOn(Schedulers.io())//为上边设置异步线程
        .observeOn(AndroidSchedulers.mainThread())//为下面代码设置主线程
        .subscribe(new Consumer<ProjectBean>(){
            @Override
            public void accept(ProjectBean projectBean) throws Exception{
                //更新UI
            }
        })
}
RxBinding 防抖 + 网络嵌套 flatMap解决嵌套问题
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1' // 操作功能防抖
Button testButton = findviewById(R.id.bt_anti_shake);
RxView.clicks(testButton)
    .throttleFirst(2000,TimeUnit.MILLISECONDS)//2秒钟之内 响应一次
    //给下边切换异步线程
    .observeOn(Schedulers.io())
    .faltMap(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 {
        return Observable.fromIterable(projectBean.getData()); // 我自己搞一个发射器 发多次 10
        }
    })
    .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 {
        	Log.d(TAG, "accept: " + projectItem);
        }
    });
一行代码实现注册登录流程

需求:

  1. 弹出加载dialog
  2. 请求服务器注册操作
  3. 注册完成后更新UI
  4. 马上去登录服务器操作
  5. 登录完成更新UI
MyRetrofit.createRetrofit().create(IReqeustNetwork.clsss)
    .registerAction(new RegisterRequest())// todo 2.请求服务器注册操作 
    .subscribeOn(schedulers.io())// 给上面 异步
    .observeOn(AndroidSchedulers.mainThread())// 给下面分配主线程
    .doOnNext(new Consumer<RegisterResponse>()){
    	@Override
    	public void accept(RegisterResponse registerResponse) throws Exception{
         // todo 3.注册完成之后,更新注册UI
        }
	})
    // todo 4.马上去登录服务器操作
    .observeOn(Schedules.io())// 给下面分配了异步线程
    .flatMap(new Function<RegisterResponse,ObservableSource<LoginResponse>(){
        @Override
        public ObservableSource<LoginResponse> apply(RegisterResponse registerResponse) throws Exception{
            // todo 5
            Observable<LoginResponse> loginResponseObservable = MyRetrofit.createRetrofit().create(IReqeustNetwork.class).loginAction(new LoginRequest());
            return loginResponseObservable;
        }
    })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Observer<LoginResponse>(){
       // 一定是主线程,为什么,因为 subscribe 马上调用onSubscribe

        @Override
        public void onSubscribe(Disposable d){
            // TODO 1
            progressDialog=new ProgressDialog(context);
            progressDialog.show();
            disposable=d;
        }
        @Override
        public onNext(LoginResponse loginresponse){
           // TODO 6.登录完成之后,更新登录的UI

        }
        @Override
        public void onError(Throwable e) {

        }

        // todo 7
        @Override
        public void onComplete() {
            // 杀青了
            if (progressDialog != null) {
                 progressDialog.dismiss();
            }
        }
    })

RxJava的Hook点

  1. map操作符源码

    @CheckReturnValue
    @SchedulerSupport(SchedulerSupport.NONE)
    public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
        ObjectHelper.requireNonNull(mapper, "mapper is null");
        return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));
    }
    
  2. RxJavaPlugins.onAssembly中f默认为null

    @NonNull
    public static <T> Observable<T> onAssembly(@NonNull Observable<T> source) {
       Function<? super Observable, ? extends Observable> f = onObservableAssembly;
       if (f != null) {
           return apply(f, source);
       }
       return source;
    }
    
  3. 通过RxJavaPlugins.setOnObservableAssembly方法设置f,在apply方法中执行全局的hook点

    RxJavaPlugins.setOnObservableAssembly(new Function<Observable,Observable>(){
        @Override
        public Observable apply(Observable observable) throws Exception{
            //整个项目全局监听,到底有多少地方使用了RxJava
            return observable;
        }
    })
    

通过代码分析RxJava观察者模式实现流程

// 结论: new ObservableCreate() {source == 自定义source}
// 2:Observable创建过程 源码分析
Observable.create(
	// 自定义source
    new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(ObservableEmitter<String> emitter) throws Exception {
        	// 发射器.onNext
            emitter.onNext("A");
        }
    })
    // 3:subscribe订阅过程 源码分析
    // ObservableCreate. subscribe
    .subscribe(
    	// 自定义观察者
        // 1:Observer 源码看看
        new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onNext(String s) {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {

        }
    });
Observable创建过程时序图

在这里插入图片描述

Observable 与 Observer 订阅的过程时序图

在这里插入图片描述

通过map操作符查看源码实现封包裹拆包裹流程
 Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> e) throws Exception {
                e.onNext("next");
                e.onComplete();
            }
        })

        // ↓ObservableCreate.map   包裹模型中 最里面
        .map(new Function<String, Integer>() {
            @Override
            public Integer apply(String s) throws Exception {
                return 45454;
            }
        })

        // ObservableMap.map
        .map(new Function<Integer, Boolean>() {
            @Override
            public Boolean apply(Integer integer) throws Exception {
                return true;
            }
        })

        // ↓包裹模型中最外面   往上走↑的时候在一层 层的剥开
        // ObservableMap.subscribe
        .subscribe(new Observer<Boolean>() {
            @Override
            public void onSubscribe(Disposable d) { }

            @Override
            public void onNext(Boolean bool) {
                Log.d(Flag.TAG, "onNext bool:" + bool);
            }

            @Override
            public void onError(Throwable e) { }

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

在这里插入图片描述

在这里插入图片描述

线程切换流程

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值