在上篇文章中讲的是关于 Rxjava 的基础篇, 今天来讲讲多种操作符的具体内容, 操作符太多了, 大家准备好啊, 耐心看~
操作符
实用操作符
1,ObserveOn
指定观察者的线程, 例如在 Android 访问网络后, 数据需要主线程消费, 那么将观察者的线程切换到主线就需要 ObserveOn 操作符. 每次指定一次都会生效.
2,subscribeOn
指定被观察者的线程, 即数据源发生的线程. 例如在 Android 访问网络时, 需要将线程切换到子线程. 多次指定只有第一次有效.
3,doOnEach
数据源 (Observable) 每发送一次数据, 就调用一次.
4,doOnNext
数据源每次调用 onNext() 之前都会先回调该方法.
5,doOnError
数据源每次调用 onError() 之前会回调该方法.
6,doOnComplete
数据源每次调用 onComplete() 之前会回调该方法
7,doOnSubscribe
数据源每次调用 onSubscribe() 之后会回调该方法
8,doOnDispose
数据源每次调用 dispose() 之后会回调该方法
其他的见官网吧, 不难
实用操作符
对数据源过滤操作符
主要讲对数据源进行选择和过滤的常用操作符
1,skip(跳过)
可以作用于 Flowable,Observable, 表示源发射数据前, 跳过多少个. 例如下面跳过前四个:
- Observable<Integer> source = Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
- source.skip(4)
- .subscribe(System.out::print);
打印结果: 5678910
- Observable<Integer> source = Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
- source.skipLast(4)
- .subscribe(System.out::print);
打印结果: 1 2 3 4 5 6
skipLast(n)操作表示从流的尾部跳过 n 个元素.
2,debounce(去抖动)
可作用于 Flowable,Observable. 在 Android 开发, 通常为了防止用户重复点击而设置标记位, 而通过 RxJava 的 debounce 操作符可以有效达到该效果. 在规定时间内, 用户重复点击只有最后一次有效,
- Observable<String> source = Observable.create(emitter -> {
- emitter.onNext("A");
- Thread.sleep(1_500);
- emitter.onNext("B");
- Thread.sleep(500);
- emitter.onNext("C");
- Thread.sleep(250);
- emitter.onNext("D");
- Thread.sleep(2_000);
- emitter.onNext("E");
- emitter.onComplete();
- });
- source.subscribeOn(Schedulers.io())
- .debounce(1, TimeUnit.SECONDS)
- .blockingSubscribe(
- item -> System.out.print(item+" "),
- Throwable::printStackTrace,
- () -> System.out.println("onComplete"));
打印: A D E onComplete
上文代码中, 数据源以一定的时间间隔发送 A,B,C,D,E. 操作符 debounce 的时间设为 1 秒, 发送 A 后 1.5 秒并没有发射其他数据, 所以 A 能成功发射. 发射 B 后, 在 1 秒之内, 又发射了 C 和 D, 在 D 之后的 2 秒才发射 E, 所有 B,C 都失效, 只有 D 有效; 而 E 之后已经没有其他数据流了, 所有 E 有效.
3,distinct(去重)
可作用于 Flowable,Observable, 去掉数据源重复的数据.
- Observable.just(2, 3, 4, 4, 2, 1)
- .distinct()
- .subscribe(System.out::print);
- // 打印: 2 3 4 1
- Observable.just(1, 1, 2, 1, 2, 3, 3, 4)
- .distinctUntilChanged()
- .subscribe(System.out::print);
- // 打印: 1 2 1 2 3 4
distinctUntilChanged()去掉相邻重复数据.
4,elementAt(获取指定位置元素)
可作用于 Flowable,Observable, 从数据源获取指定位置的元素, 从 0 开始.
- Observable.just(2,4,3,1,5,8)
- .elementAt(0)
- .subscribe(integer ->
- Log.d("TAG","elmentAt->"+integer));
打印: 2
- Observable<String> source = Observable.just("Kirk", "Spock", "Chekov", "Sulu");
- Single<String> element = source.elementAtOrError(4);
- element.subscribe(
- name -> System.out.println("onSuccess will not be printed!"),
- error -> System.out.println("onError:" + error));
打印: onSuccess will not be printed!
elementAtOrError: 指定元素的位置超过数据长度, 则发射异常.
5,filter(过滤)
可作用于 Flowable,Observable,Maybe,Single. 在 filter 中返回表示发射该元素, 返回 false 表示过滤该数据.
- Observable.just(1, 2, 3, 4, 5, 6)
- .filter(x -> x % 2 == 0)
- .subscribe(System.out::print);
打印: 2 4 6
6,first(第一个)
作用于 Flowable,Observable. 发射数据源第一个数据, 如果没有则发送默认值.
- Observable<String> source = Observable.just("A", "B", "C");
- Single<String> firstOrDefault = source.first("D");
- firstOrDefault.subscribe(System.out::println);
打印: A
- Observable<String> emptySource = Observable.empty();
- Single<String> firstOrError = emptySource.firstOrError();
- firstOrError.subscribe(
- element -> System.out.println("onSuccess will not be printed!"),
- error -> System.out.println("onError:" + error));
打印: onError: java.util.NoSuchElementException
和 firstElement 的区别是 first 返回的是 Single, 而 firstElement 返回 Maybe.firstOrError 在没有数据会返回异常.
7,last(最后一个)
last,lastElement,lastOrError 与 fist,firstElement,firstOrError 相对应.
- Observable<String> source = Observable.just("A", "B", "C");
- Single<String> lastOrDefault = source.last("D");
- lastOrDefault.subscribe(System.out::println);
- // 打印: C
- Observable<String> source = Observable.just("A", "B", "C");
- Maybe<String> last = source.lastElement();
- last.subscribe(System.out::println);
- // 打印: C
- Observable<String> emptySource = Observable.empty();
- Single<String> lastOrError = emptySource.lastOrError();
- lastOrError.subscribe(
- element -> System.out.println("onSuccess will not be printed!"),
- error -> System.out.println("onError:" + error));
- // 打印: onError: java.util.NoSuchElementException
- 8,ignoreElements & ignoreElement(忽略元素)
ignoreElements 作用于 Flowable,Observable.ignoreElement 作用于 Maybe,Single. 两者都是忽略掉数据, 返回完成或者错误时间.
- Single<Long> source = Single.timer(1, TimeUnit.SECONDS);
- Completable completable = source.ignoreElement();
- completable.doOnComplete(() -> System.out.println("Done!"))
- .blockingAwait();
- // 1 秒后打印: Donde!
- Observable<Long> source = Observable.intervalRange(1, 5, 1, 1, TimeUnit.SECONDS);
- Completable completable = source.ignoreElements();
- completable.doOnComplete(() -> System.out.println("Done!"))
- .blockingAwait();
- // 五秒后打印: Done!
- 9,ofType(过滤掉类型)
作用于 Flowable,Observable,Maybe, 过滤掉类型.
- Observable<Number> numbers = Observable.just(1, 4.0, 3, 2.71, 2f, 7);
- Observable<Integer> integers = numbers.ofType(Integer.class);
- integers.subscribe((Integer x) -> System.out.print(x+" "));
- // 打印: 1 3 7
- 10,sample
作用于 Flowable,Observable, 在一个周期内发射最新的数据.
- Observable<String> source = Observable.create(emitter -> {
- emitter.onNext("A");
- Thread.sleep(500);
- emitter.onNext("B");
- Thread.sleep(200);
- emitter.onNext("C");
- Thread.sleep(800);
- emitter.onNext("D");
- Thread.sleep(600);
- emitter.onNext("E");
- emitter.onComplete();
- });
- source.subscribeOn(Schedulers.io())
- .sample(1, TimeUnit.SECONDS)
- .blockingSubscribe(
- item -> System.out.print(item+" "),
- Throwable::printStackTrace,
- () -> System.out.print("onComplete"));
- // 打印: C D onComplete
与 debounce 的区别是, sample 是以时间为周期的发射, 一秒又一秒内的最新数据. 而 debounce 是最后一个有效数据开始.
11,throttleFirst & throttleLast & throttleWithTimeout
作用于 Flowable,Observable.throttleLast 与 smaple 一致, 而 throttleFirst 是指定周期内第一个数据. throttleWithTimeout 与 debounce 一致.
- Observable<String> source = Observable.create(emitter -> {
- emitter.onNext("A");
- Thread.sleep(500);
- emitter.onNext("B");
- Thread.sleep(200);
- emitter.onNext("C");
- Thread.sleep(800);
- emitter.onNext("D");
- Thread.sleep(600);
- emitter.onNext("E");
- emitter.onComplete();
- });
- source.subscribeOn(Schedulers.io())
- .throttleFirst(1, TimeUnit.SECONDS)
- .blockingSubscribe(
- item -> System.out.print(item+" "),
- Throwable::printStackTrace,
- () -> System.out.print("onComplete"));
- // 打印: A D onComplete
- source.subscribeOn(Schedulers.io())
- .throttleLast(1, TimeUnit.SECONDS)
- .blockingSubscribe(
- item -> System.out.print(item+" "),
- Throwable::printStackTrace,
- () -> System.out.print("onComplete"));
- // 打印: C D onComplete
- 12,throttleLatest
之所以拿出来单独说, 我看不懂官网的解释. 然后看别人的文章: throttleFirst+throttleLast 的组合? 开玩笑的吧. 个人理解是: 如果源的第一个数据总会被发射, 然后开始周期计时, 此时的效果就会跟 throttleLast 一致.
- Observable<String> source = Observable.create(emitter -> {
- emitter.onNext("A");
- Thread.sleep(500);
- emitter.onNext("B");
- Thread.sleep(200);
- emitter.onNext("C");
- Thread.sleep(200);
- emitter.onNext("D");
- Thread.sleep(400);
- emitter.onNext("E");
- Thread.sleep(400);
- emitter.onNext("F");
- Thread.sleep(400);
- emitter.onNext("G");
- Thread.sleep(2000);
- emitter.onComplete();
- });
- source.subscribeOn(Schedulers.io())
- .throttleLatest(1, TimeUnit.SECONDS)
- .blockingSubscribe(
- item -> Log.e("RxJava",item),
- Throwable::printStackTrace,
- () -> Log.e("RxJava","finished"));
打印结果:
13,take & takeLast
作用于 Flowable,Observable,take 发射前 n 个元素; takeLast 发射后 n 个元素.
- Observable<Integer> source = Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
- source.take(4)
- .subscribe(System.out::print);
- // 打印: 1 2 3 4
- source.takeLast(4)
- .subscribe(System.out::println);
- // 打印: 7 8 9 10
- 14,timeout(超时)
作用于 Flowable,Observable,Maybe,Single,Completabl. 后一个数据发射未在前一个元素发射后规定时间内发射则返回超时异常.
- Observable<String> source = Observable.create(emitter -> {
- emitter.onNext("A");
- Thread.sleep(800);
- emitter.onNext("B");
- Thread.sleep(400);
- emitter.onNext("C");
- Thread.sleep(1200);
- emitter.onNext("D");
- emitter.onComplete();
- });
- source.timeout(1, TimeUnit.SECONDS)
- .subscribe(
- item -> System.out.println("onNext:" + item),
- error -> System.out.println("onError:" + error),
- () -> System.out.println("onComplete will not be printed!"));
- // 打印:
- // onNext: A
- // onNext: B
- // onNext: C
- // onError: java.util.concurrent.TimeoutException:
- The source did not signal an event for 1 seconds
- and has been terminated.
连接操作符
通过连接操作符, 将多个被观察数据 (数据源) 连接在一起.
1,startWith
可作用于 Flowable,Observable. 将指定数据源合并在另外数据源的开头.
- Observable<String> names = Observable.just("Spock", "McCoy");
- Observable<String> otherNames = Observable.just("Git", "Code","8");
- names.startWith(otherNames).subscribe(item -> Log.d(TAG,item));
- // 打印:
- RxJava: Git
- RxJava: Code
- RxJava: 8
- RxJava: Spock
- RxJava: McCo
- 2,merge
可作用所有数据源类型, 用于合并多个数据源到一个数据源.
- Observable<String> names = Observable.just("Hello", "world");
- Observable<String> otherNames = Observable.just("Git", "Code","8");
- Observable.merge(names,otherNames).subscribe(name -> Log.d(TAG,name));
- // 也可以是
- //names.mergeWith(otherNames).subscribe(name -> Log.d(TAG,name));
- // 打印:
- RxJava: Hello
- RxJava: world
- RxJava: Git
- RxJava: Code
- RxJava: 8
merge 在合并数据源时, 如果一个合并发生异常后会立即调用观察者的 onError 方法, 并停止合并. 可通过 mergeDelayError 操作符, 将发生的异常留到最后处理.
- Observable<String> names = Observable.just("Hello", "world");
- Observable<String> otherNames = Observable.just("Git", "Code","8");
- Observable<String> error = Observable.error(
- new NullPointerException("Error!"));
- Observable.mergeDelayError(names,error,otherNames).subscribe(
- name -> Log.d(TAG,name), e->Log.d(TAG,e.getMessage()));
- // 打印:
- RxJava: Hello
- RxJava: world
- RxJava: Git
- RxJava: Code
- RxJava: 8
- RxJava: Error!
- 3,zip
可作用于 Flowable,Observable,Maybe,Single. 将多个数据源的数据一个一个的合并在一起哇. 当其中一个数据源发射完事件之后, 若其他数据源还有数据未发射完毕, 也会停止.
- Observable<String> names = Observable.just("Hello", "world");
- Observable<String> otherNames = Observable.just("Git", "Code", "8");
- names.zipWith(otherNames, (first, last) -> first + "-" + last)
- .subscribe(item -> Log.d(TAG, item));
- // 打印:
- RxJava: Hello-Git
- RxJava: world-Code
- 4,combineLatest
可作用于 Flowable, Observable. 在结合不同数据源时, 发射速度快的数据源最新 item 与较慢的相结合. 如下时间线, Observable-1 发射速率快, 发射了 65,Observable-2 才发射了 C, 那么两者结合就是 C5.
5,switchOnNext
一个发射多个小数据源的数据源, 这些小数据源发射数据的时间发生重复时, 取最新的数据源.
变换操作符
变化数据源的数据, 并转化为新的数据源.
1,buffer
作用于 Flowable,Observable. 指将数据源拆解含有长度为 n 的 list 的多个数据源, 不够 n 的成为一个数据源.
- Observable.range(0, 10)
- .buffer(4)
- .subscribe((List<Integer> buffer) -> System.out.println(buffer));
- // 打印:
- // [0, 1, 2, 3]
- // [4, 5, 6, 7]
- // [8, 9]
- 2,cast
作用于 Flowable,Observable,Maybe,Single. 将数据元素转型成其他类型, 转型失败会抛出异常.
- Observable<Number> numbers = Observable.just(1, 4.0, 3f, 7, 12, 4.6, 5);
- numbers.filter((Number x) -> Integer.class.isInstance(x))
- .cast(Integer.class)
- .subscribe((Integer x) -> System.out.println(x));
- // prints:
- // 1
- // 7
- // 12
- // 5
- 3,concatMap
作用于 Flowable,Observable,Maybe. 将数据源的元素作用于指定函数后, 将函数的返回值有序的存在新的数据源.
- Observable.range(0, 5)
- .concatMap(i -> {
- long delay = Math.round(Math.random() * 2);
- return Observable.timer(delay, TimeUnit.SECONDS).map(n -> i);
- })
- .blockingSubscribe(System.out::print);
- // prints 01234
- 4,concatMapDelayError
与 concatMap 作用相同, 只是将过程发送的所有错误延迟到最后处理.
- Observable.intervalRange(1, 3, 0, 1, TimeUnit.SECONDS)
- .concatMapDelayError(x -> {
- if (x.equals(1L)) return Observable.error(new IOException("Something went wrong!"));
- else return Observable.just(x, x * x);
- })
- .blockingSubscribe(
- x -> System.out.println("onNext:" + x),
- error -> System.out.println("onError:" + error.getMessage()));
- // prints:
- // onNext: 2
- // onNext: 4
- // onNext: 3
- // onNext: 9
- // onError: Something went wrong!
- 5,concatMapCompletable
作用于 Flowable,Observable. 与 contactMap 类似, 不过应用于函数后, 返回的是 CompletableSource. 订阅一次并在所有 CompletableSource 对象完成时返回一个 Completable 对象.
- Observable<Integer> source = Observable.just(2, 1, 3);
- Completable completable = source.concatMapCompletable(x -> {
- return Completable.timer(x, TimeUnit.SECONDS)
- .doOnComplete(() -> System.out.println("Info: Processing of item \"" + x + "\" completed"));
- });
- completable.doOnComplete(() -> System.out.println("Info: Processing of all items completed"))
- .blockingAwait();
- // prints:
- // Info: Processing of item "2" completed
- // Info: Processing of item "1" completed
- // Info: Processing of item "3" completed
- // Info: Processing of all items completed
- 6,concatMapCompletableDelayError
与 concatMapCompletable 作用相同, 只是将过程发送的所有错误延迟到最后处理.
- Observable<Integer> source = Observable.just(2, 1, 3);
- Completable completable = source.concatMapCompletableDelayError(x -> {
- if (x.equals(2)) {
- return Completable.error(new IOException("Processing of item \"" + x + "\" failed!"));
- } else {
- return Completable.timer(1, TimeUnit.SECONDS)
- .doOnComplete(() -> System.out.println("Info: Processing of item \"" + x + "\" completed"));
- }
- });
- completable.doOnError(error -> System.out.println("Error:" + error.getMessage()))
- .onErrorComplete()
- .blockingAwait();
- // prints:
- // Info: Processing of item "1" completed
- // Info: Processing of item "3" completed
- // Error: Processing of item "2" failed!
- ContactMap
- 8,flatMap
作用于 Flowable,Observable,Maybe,Single. 与 contactMap 类似, 只是 contactMap 的数据发射是有序的, 而 flatMap 是无序的.
- Observable.just("A", "B", "C")
- .flatMap(a -> {
- return Observable.intervalRange(1, 3, 0, 1, TimeUnit.SECONDS)
- .map(b -> '(' + a + "," + b + ')');
- })
- .blockingSubscribe(System.out::println);
- // prints (not necessarily in this order):
- // (A, 1)
- // (C, 1)
- // (B, 1)
- // (A, 2)
- // (C, 2)
- // (B, 2)
- // (A, 3)
- // (C, 3)
- // (B, 3)
9,flatMapXXX 和 contactMapXXX
太多了, 减少篇幅, 大家感兴趣自己查阅官网吧. 功能与 flatMap 和 contactMap 类似.
10,flattenAsFlowable & flattenAsObservable
作用于 Maybe,Single, 将其转化为 Flowable, 或 Observable.
- Single<Double> source = Single.just(2.0);
- Flowable<Double> flowable = source.flattenAsFlowable(x -> {
- return List.of(x, Math.pow(x, 2), Math.pow(x, 3));
- });
- flowable.subscribe(x -> System.out.println("onNext:" + x));
- // prints:
- // onNext: 2.0
- // onNext: 4.0
- // onNext: 8.0
- 11,groupBy
作用于 Flowable,Observable. 根据一定的规则对数据源进行分组.
- Observable<String> animals = Observable.just(
- "Tiger", "Elephant", "Cat", "Chameleon", "Frog", "Fish", "Turtle", "Flamingo");
- animals.groupBy(animal -> animal.charAt(0), String::toUpperCase)
- .concatMapSingle(Observable::toList)
- .subscribe(System.out::println);
- // prints:
- // [TIGER, TURTLE]
- // [ELEPHANT]
- // [CAT, CHAMELEON]
- // [FROG, FISH, FLAMINGO]
- 12,scan
作用于 Flowable,Observable. 对数据进行相关联操作, 例如聚合等.
- Observable.just(5, 3, 8, 1, 7)
- .scan(0, (partialSum, x) -> partialSum + x)
- .subscribe(System.out::println);
- // prints:
- // 0
- // 5
- // 8
- // 16
- // 17
- // 24
- 13,Windows
对数据源发射出来的数据进行收集, 按照指定的数量进行分组, 以组的形式重新发射.
- Observable.range(1, 4)
- // Create Windows containing at most 2 items, and skip 3 items before starting a new Windows.
- .Windows(2)
- .flatMapSingle(Windows -> {
- return Windows.map(String::valueOf)
- .reduce(new StringJoiner(",", "[", "]"), StringJoiner::add);
- })
- .subscribe(System.out::println);
- // prints:
- // [1, 2]
- // [3, 4]
错误处理操作符
1,onErrorReturn
作用于 Flowable,Observable,Maybe,Single. 但调用数据源的 onError 函数后会回到该函数, 可对错误进行处理, 然后返回值, 会调用观察者 onNext()继续执行, 执行完调用 onComplete()函数结束所有事件的发射.
- Single.just("2A")
- .map(v -> Integer.parseInt(v, 10))
- .onErrorReturn(error -> {
- if (error instanceof NumberFormatException) return 0;
- else throw new IllegalArgumentException();
- })
- .subscribe(
- System.out::println,
- error -> System.err.println("onError should not be printed!"));
- // prints 0
- 2,onErrorReturnItem
与 onErrorReturn 类似, onErrorReturnItem 不对错误进行处理, 直接返回一个值.
- Single.just("2A")
- .map(v -> Integer.parseInt(v, 10))
- .onErrorReturnItem(0)
- .subscribe(
- System.out::println,
- error -> System.err.println("onError should not be printed!"));
- // prints 0
- 3,onExceptionResumeNext
可作用于 Flowable,Observable,Maybe.onErrorReturn 发生异常时, 回调 onComplete()函数后不再往下执行, 而 onExceptionResumeNext 则是要在处理异常的时候返回一个数据源, 然后继续执行, 如果返回 null, 则调用观察者的 onError()函数.
- Observable.create((ObservableOnSubscribe<Integer>) e -> {
- e.onNext(1);
- e.onNext(2);
- e.onNext(3);
- e.onError(new NullPointerException());
- e.onNext(4);
- })
- .onErrorResumeNext(throwable -> {
- Log.d(TAG, "onErrorResumeNext");
- return Observable.just(4);
- })
- .subscribe(new Observer<Integer>() {
- @Override
- public void onSubscribe(Disposable d) {
- Log.d(TAG, "onSubscribe");
- }
- @Override
- public void onNext(Integer integer) {
- Log.d(TAG, "onNext" + integer);
- }
- @Override
- public void onError(Throwable e) {
- Log.d(TAG, "onError");
- }
- @Override
- public void onComplete() {
- Log.d(TAG, "onComplete");
- }
- });
结果:
onExceptionResumeNext 操作符也是类似的, 只是捕获 Exception.
4,retry
可作用于所有的数据源, 当发生错误时, 数据源重复发射 item, 直到没有异常或者达到所指定的次数.
- boolean first=true;
- Observable.create((ObservableOnSubscribe<Integer>) e -> {
- e.onNext(1);
- e.onNext(2);
- if (first){
- first=false;
- e.onError(new NullPointerException());
- }
- })
- .retry(9)
- .subscribe(new Observer<Integer>() {
- @Override
- public void onSubscribe(Disposable d) {
- Log.d(TAG, "onSubscribe");
- }
- @Override
- public void onNext(Integer integer) {
- Log.d(TAG, "onNext" + integer);
- }
- @Override
- public void onError(Throwable e) {
- Log.d(TAG, "onError");
- }
- @Override
- public void onComplete() {
- Log.d(TAG, "onComplete");
- }
- });
结果:
5,retryUntil
作用于 Flowable,Observable,Maybe. 与 retry 类似, 但发生异常时, 返回值是 false 表示继续执行(重复发射数据),true 不再执行, 但会调用 onError 方法.
- Observable.create((ObservableOnSubscribe<Integer>) e -> {
- e.onNext(1);
- e.onNext(2);
- e.onError(new NullPointerException());
- e.onNext(3);
- e.onComplete();
- })
- .retryUntil(() -> true)
- .subscribe(new Observer<Integer>() {
- @Override
- public void onSubscribe(Disposable d) {
- Log.d(TAG, "onSubscribe");
- }
- @Override
- public void onNext(Integer integer) {
- Log.d(TAG, "onNext" + integer);
- }
- @Override
- public void onError(Throwable e) {
- Log.d(TAG, "onError");
- }
- @Override
- public void onComplete() {
- Log.d(TAG, "onComplete");
- }
- });
结果:
retryWhen 与此类似, 但其判断标准不是 BooleanSupplier 对象的 getAsBoolean()函数的返回值. 而是返回的 Observable 或 Flowable 是否会发射异常事件.
总结
终于结束了~ 太多操作符太累了, 看得心好累. 还是根据实际开发需要查阅文档才是正确的姿势. 本文只是 RxJava 冰山一角, 更多请参阅官网. 同时不建议立马在项目上实践, 给它点时间报 bug.
参阅官网
如果你看到了这, 点个赞, 收下我双膝. 如果文章有误, 帮忙指正, 谢谢大佬们.
来源: http://www.jianshu.com/p/eeff6bbfd2a5