RxJava使用简史(一)RxJava1的回顾

前言

使用RxJava 已经有一年多的时间,从 RxJava 1.0 +Retrofit 2.0 网络请求框架,包括常用的 RxBus,RxPermission 等,到后面的RxJava2.0+Retrofit2.0。然而始终没有认真细致的去归纳总结,基于这个缘由,本文将由浅入深,由Rx的基本用法,到RxJava和Retrofit的封装,到Rx的源码分析,做一次系统的学习。

https://github.com/ReactiveX/RxJava

本文将分为三个方面阐述:

  • RxJava 是什么
  • RxJava 基本用法
  • RxJava 的用途

一:RxJava的认识

想要用一句话总结RxJava,或许只有作者的那句话才能精准概括了:RxJava实现了jvm的响应式扩展,通过观察序列来实现异步和基于事件的库。
如果要加上更细致的阐述那就是:它扩展了观察者模式,支持数据或者事件的序列,添加了一系列的操作符,允许你使用声明的方式组合序列,同时处理了线程、同步、线程安全、和并发的问题。

RxJava 依赖代码

compile “io.reactivex:rxjava:1.2.3”
compile “io.reactivex:rxandroid:1.2.1”

既然是观察者模式,那么就必然有观察者和被观察者,在RxJava中,有两个类需要搞清楚

Observable :被观察者,Observer :观察者。
二者通过 subscribe() 方法来实现订阅的关系,这样一来 Observable 可以在需要的时候发送事件通知 Observer。

Observable 的创建
    //创建一个 Observable (被观察者)
    Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
        @Override
        public void call(Subscriber<? super String> subscriber) {
            subscriber.onNext("hi");
            subscriber.onCompleted();
        }
    });

创建 Observable 的时候,需要传递一个 OnSubscribe 对象 ,这个对象的指定了一个回调,当订阅事件发生的时候,call 方法里面的内容就会被调用。在回调的方法中 可以看到 Subscriber 对象,这个对象实现了 Observer 和 Subscription 接口,事实上,它是 Observer(观察者) 的升级版。

而 Observable 创建的时候做了什么呢?

 public static <T> Observable<T> create(OnSubscribe<T> f) {
    return new Observable<T>(RxJavaHooks.onCreate(f));
}

RxJavaHooks 的 onCreate() 返回了一个 OnSubscribe 对象,OnSubscribe 是 Action1 的子类,是一个只有一个 call() 方法的接口。RxJavaHooks 的内部,则调用了 RxJavaHooks 的一个接口 Func1 的 call()方法的回调。

Observer 的创建
    //创建一个 Observer (观察者)
    Observer observer = new Observer() {
        @Override
        public void onCompleted() {
        }

        @Override
        public void onError(Throwable e) {
        }

        @Override
        public void onNext(Object o) {
        }
    };

或者可以这样写:

     Subscriber subscriber = new Subscriber() {
        @Override
        public void onCompleted() {
        }

        @Override
        public void onError(Throwable e) {
        }

        @Override
        public void onNext(Object o) {
        }
    };

Observer只是一个接口,他们的作用是一样的,区别在于 Subscriber 比 Observer 多了两个方法 onStart() 和 unsubscribe(), 前者是在事件还没有发送之前调用的,可以进行一些准备的动作,后者则是用于取消订阅,在发生订阅行为的时候,被观察者会持有观察者的引用,如果在页面销毁或者view销毁或者其他情况下没有进行解绑,则会发生内存泄漏。

订阅
  //订阅
    observable.subscribe(observer);

这里有个奇怪的现象,你会发现是被观察者订阅了观察者。之所以这样实现,是为了更好的设计。
而订阅行为到底干了什么,为什么要传递进去一个接口呢?看下源码

public final Subscription subscribe(final Observer<? super T> observer) {
    if (observer instanceof Subscriber) {
        return subscribe((Subscriber<? super T>)observer);
    }
    if (observer == null) {
        throw new NullPointerException("observer is null");
    }
    return subscribe(new ObserverSubscriber<T>(observer));
}

重点看下 observable 的 subscribe 方法,他需要传递一个 ObserverSubscriber的对象 ,它Subscriber 的子类,而且提供了一个构造函数来传递 observer。
在真正的 subscribe 方法中,我们可以看到这么一句话:

static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {
 // validate and proceed
    if (subscriber == null) {
        throw new IllegalArgumentException("subscriber can not be null");
    }
    if (observable.onSubscribe == null) {
        throw new IllegalStateException("onSubscribe function can not be null.");
        /*
         * the subscribe function can also be overridden but generally that's not the appropriate approach
         * so I won't mention that in the exception
         */
    }

    // new Subscriber so onStart it
    subscriber.onStart();

    /*
     * See https://github.com/ReactiveX/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls
     * to user code from within an Observer"
     */
    // if not already wrapped
    if (!(subscriber instanceof SafeSubscriber)) {
        // assign to `observer` so we return the protected version
        subscriber = new SafeSubscriber<T>(subscriber);
    }

    // The code below is exactly the same an unsafeSubscribe but not used because it would
    // add a significant depth to already huge call stacks.
    try {
        // allow the hook to intercept and/or decorate
        RxJavaHooks.onObservableStart(observable, observable.onSubscribe).call(subscriber);
        return RxJavaHooks.onObservableReturn(subscriber);
    } catch (Throwable e) {
        // special handling for certain Throwable/Error/Exception types
        Exceptions.throwIfFatal(e);
        // in case the subscriber can't listen to exceptions anymore
        if (subscriber.isUnsubscribed()) {
            RxJavaHooks.onError(RxJavaHooks.onObservableError(e));
        } else {
            // if an unhandled error occurs executing the onSubscribe we will propagate it
            try {
                subscriber.onError(RxJavaHooks.onObservableError(e));
            } catch (Throwable e2) {
                Exceptions.throwIfFatal(e2);
                // if this happens it means the onError itself failed (perhaps an invalid function implementation)
                // so we are unable to propagate the error correctly and will just throw
                RuntimeException r = new OnErrorFailedException("Error occurred attempting to subscribe [" + e.getMessage() + "] and then again while trying to pass to onError.", e2);
                // TODO could the hook be the cause of the error in the on error handling.
                RxJavaHooks.onObservableError(r);
                // TODO why aren't we throwing the hook's return value.
                throw r; // NOPMD
            }
        }
        return Subscriptions.unsubscribed();
    }
}

subscriber.onStart(); 在 observable 中 调用了 subscriber 的 onStart()方法,
RxJavaHooks.onObservableStart(observable, observable.onSubscribe).call(subscriber); 这个方法,其实就是OnSubscribe对call 方法的调用。

经过上面的三个步骤,就完成了一次RxJava的基本使用。然而事实上,不管是 observable 的创建或者是 observer 或者 Subscriber ,再或者绑定的使用,都有很多种方法可以选择,事实上,要根据业务逻辑或者不同的场景来选择使用。比如:

  Observable<String> just = Observable.just( "are", "u", "ok");
    just.subscribe(new Subscriber<String>() {
        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onNext(String s) {
            Log.i(TAG, s);
        }
    });

通过just 将传入的参数依次的发送出来,这样,在 Subscriber 的回调中(onNext),就可以依次的打印出那几个字符串。
假定有一个数据源,我需要依次发送数据源里面的数据,from方法则会很恰当,就像这样:

    String[]  array = new String[]{"are","u","ok"};
    Observable<String> observableStr = Observable.from(array);
    observableStr.subscribe(new Subscriber<String>() {
        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onNext(String s) {

        }
    });

同样的,Subscribe() 方法也可以通过Action来实现某些不完全的定义,比如这样:

    Action1<String> action1 = new Action1<String>() {
        @Override
        public void call(String s) {
            Log.i(TAG, s);
        }
    };
    observableStr.subscribe(action1);
Scheduler 调度器

通过 Schduler 调度器来指定某段代码运行在哪个线程之中,因为在日常开发中,我们总是会将耗时的请求放在后台,通过回调在前台更新ui,基于这些重要的线程控制,Scheduler 提供了一系列的方法来进行线程切换。诸如:

    //直接运行,即在当前的线程运行
    Schedulers.immediate();
    //计算的线程,主要用于事件轮询,回调的处理等。不能进行耗时的操作。
    Schedulers.computation();
    //开启一个新的线程,并且运行在新线程
    Schedulers.newThread();
    // 读写、网络、等耗时操作
    Schedulers.io();
    //Android 主线程 
    AndroidSchedulers.mainThread();

Observable 提供了一些方法来指定我们需要的线程:

observableStr.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread());

subscribeOn() 方法指定了subscribe() 发生在IO线程,observeOn() 则指定了其回调发生在主线程。准确的说前者是指定事件产生的线程,后者是指定事件消费的线程。

变换

所谓变换,即把事件序列 中的对象或者整个序列进行变换,得到我想要的事件或者序列。通过一个简单的例子就可以看出来转换的强大之处了。
比如所我想加载指定路径下的ImageView

    String mImgPath = "...";
    Observable.just(mImgPath)
            .map(new Func1<String, Bitmap>() {
                @Override
                public Bitmap call(String s) {
                    Bitmap bitmap = BitmapFactory.decodeFile(s);
                    return bitmap;
                }
            })
            .subscribe(new Action1<Bitmap>() {
                @Override
                public void call(Bitmap bitmap) {
                    imageView.setImageBitmap(bitmap);
                }
            });

map()方法需要一个 Func1 的回调 ,Func1是一个简单的接口,和 Action 不同的地方在于,它是有返回值的。这就达到了转换的目的。我们看到,我们发送事件的只是一个字符串,通过转换,在我们需要Bitmap的时候,在map() 中把字符串做了转换。

除此之外,还有一个转换的方法 flatMap(),与map()方法不同的地方在于,flatMap中返回的是一个 Observable 对象。通过 flatMap 将事件进行了拆分,可以进行更加细致和精准的处理:
假如有这个一个类,在发起事件的时候传递整个类的对象,最后我想要的是String content,这种情况使用flatMap 就更加方便了。

public class DataBean implements Serializable {
public Data data;
public String message;
public int code;

class Data {
    public String title;
    public Content content;
}

class Content {
    public String content;
    }
}


final List<DataBean> beanList = new ArrayList<>();
    Subscriber<String> subscriber1 = new Subscriber<String>() {
        @Override
        public void onCompleted() {
        }

        @Override
        public void onError(Throwable e) {
        }

        @Override
        public void onNext(String s) {
        }
    };

    Observable.from(beanList)
            .flatMap(new Func1<DataBean, Observable<DataBean.Content>>() {
                @Override
                public Observable<DataBean.Content> call(DataBean bean) {
                    return Observable.just(bean.data.content);
                }
            })
            .flatMap(new Func1<DataBean.Content, Observable<String>>() {
                @Override
                public Observable<String> call(DataBean.Content content) {
                    return Observable.just(content.content);
                }
            })
            .subscribe(subscriber1);

我们会发现 map 是一对一的关系,而 flatMap 是一对多的关系,通过 flatmap 可以实现很强大的功能。

小示例

假如我们需要把一个Bitmap格式的图片保存为png或者jpg文件 ,假如使用RxJava,结合上面的线程调度器,我们该怎么写呢?直接上代码吧。

 Observable.create(new SaveObservable(bitmap))
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new SaveSubscriber());


    //Observable
 private class SaveObservable implements Observable.OnSubscribe<String> {
    private Bitmap drawingCache = null;

    public SaveObservable(Bitmap drawingCache) {
        this.drawingCache = drawingCache;
    }

    @Override
    public void call(Subscriber<? super String> subscriber) {
        if (drawingCache == null) {
            subscriber.onError(new NullPointerException("获取图片失败"));
        } else {
            try {
                File imageFile = new File(imagePath,imageName);
                FileOutputStream outStream = new FileOutputStream(imageFile);
                drawingCache.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
                subscriber.onNext(Environment.getExternalStorageDirectory() + "/store");
                subscriber.onCompleted();
                outStream.flush();
                outStream.close();
            } catch (IOException e) {
                subscriber.onError(e);
            }
        }
    }
}

//Subscriber
private class SaveSubscriber extends Subscriber<String> {

    @Override
    public void onCompleted() {
      //  Toast.makeText(context, "保存成功", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onError(Throwable e) {
        Log.i(getClass().getSimpleName(), e.toString());
        Toast.makeText(context, "保存失败:" + e.toString(), Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onNext(String s) {
        Toast.makeText(context, "保存至" + s, Toast.LENGTH_SHORT).show();
    }
}

这样看来,我们的代码看起来非常的清爽,而且逻辑清晰。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值