說說RxJava怎麼走的歪路

SamanLan發表於2017-12-13

將從Rx一個最簡單的流程說起,說到map,說到SubscribeOn,說到observeOn,說到天荒地老

一個完整流程

Observable.create(new ObservableOnSubscribe<Object>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Object> e) throws Exception {
                System.out.println("工作空間");
            }
        }).subscribe(new Observer<Object>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                System.out.println("已連線觀察通道");
            }

            @Override
            public void onNext(@NonNull Object o) {
                System.out.println("接受工作空間傳送的事件");
            }

            @Override
            public void onError(@NonNull Throwable e) {
                System.out.println("出錯");
            }

            @Override
            public void onComplete() {
                System.out.println("完成");
            }
        });
複製程式碼

接下來看圖分析整個流程做了什麼

一個完整流程

文字描述:被觀察者呼叫subscribe(訂閱)觀察者,然後被觀察者通過呼叫ObservableEmitter發射器)發射各種事件(onNextonErroronComplete


轉換事件

Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
                System.out.println("工作空間。我傳送的是string型別資料");
            }
        }).map(new Function<String, Integer>() {
            @Override
            public Integer apply(@NonNull String o) throws Exception {
                System.out.println("將string轉換成int返回");
                return o.length();
            }
        }).subscribe(new Observer<Integer>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                System.out.println("已連線觀察通道");
            }

            @Override
            public void onNext(@NonNull Integer o) {
                System.out.println("接受工作空間傳送的事件,接受到的是int型別");
            }

            @Override
            public void onError(@NonNull Throwable e) {
                System.out.println("出錯");
            }

            @Override
            public void onComplete() {
                System.out.println("完成");
            }
        });
複製程式碼

可以看到,一開始的被觀察者發射的型別是String,而觀察者接受的型別是Integer型別。我要的是寶馬你卻給我電單車?WTF? 這個時候就需要用到map這個操作符了,可以相當於一箇中轉站(加工站),將被觀察者傳送過來的資料轉換成符合觀察者需要的資料,然後再將它返回給觀察者。完美! But,how it work?? 接下來看圖分析整個流程做了什麼

map流程

注:上述圖傳遞的不是ObservableEmitter,而是為了更直觀瞭解流程,而實際具體流程也差不多,只是實現不太一樣。 文字描述: ①:原始被觀察者呼叫map()的時候,重新建立了一個被觀察者(這裡稱它為Map被觀察者),然後用Map被觀察者訂閱原始觀察者。 ②:然後在訂閱成功後,原始被觀察者將訂閱一個新的觀察者(這裡稱它為Map觀察者)。 ③:然後原始被觀察者在傳送(String)訊息的時候,Map觀察者接受到(String)訊息,將(String)訊息通過apply()方法將其轉為(Integer)訊息,並通過Map被觀察者傳送給原始觀察者。 ④:apply()方法是我們自己實現的方法

Map簡單程式碼如下

public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
        return create(new ObservableOnSubscribe<R>() { 
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> e) {
                subscribe(new Observer<T>() { 
                    @Override
                    public void onNext(T var1) {
                        e.onNext(mapper.call(var1));
                    }
                });
            }
        });
    }
複製程式碼

轉換執行緒(SubscribeOn)

Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
                System.out.println("工作空間。我傳送的是string型別資料");
            }
        }).subscribeOn(Schedulers.io())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        System.out.println("已連線觀察通道");
                    }

                    @Override
                    public void onNext(@NonNull String o) {
                        System.out.println("接受工作空間傳送的事件,接受到的是int型別");
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        System.out.println("出錯");
                    }

                    @Override
                    public void onComplete() {
                        System.out.println("完成");
                    }
                });
複製程式碼

接下來看圖分析整個流程做了什麼

SubscribeOn

文字分析:和map類似的操作,但又有點不同 ①:原始被觀察者呼叫subscribeOn()的時候,重新建立了一個被觀察者(這裡稱它為subscribeOn被觀察者),然後用subscribeOn被觀察者訂閱原始觀察者。 ②:然後在訂閱成功後,進行執行緒的轉換。 ③:在subscribeOn被觀察者中呼叫原始被觀察者subscribe(ObservableEmitter<Object> e),其中的引數發射器e用的是subscribeOn被觀察者發射器

subscribeOn()簡單程式碼如下

public final Observable<T> subscribeOn(Scheduler scheduler){
            return Observable.create(new ObservableOnSubscribe<T>() {
                @Override
                public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
                    // 執行緒的轉換
                    scheduler.createWorker().schedule(new SubscribeTask() {
                        @Override
                        public void run() {
                            // source為原始被觀察者
                            source.call(e);
                        }
                    });
                }
            });
        }
複製程式碼

轉換執行緒(observeOn)

Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
                System.out.println("工作空間。我傳送的是string型別資料");
            }
        }).observeOn(Schedulers.io())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        System.out.println("已連線觀察通道");
                    }

                    @Override
                    public void onNext(@NonNull String o) {
                        System.out.println("接受工作空間傳送的事件,接受到的是int型別");
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        System.out.println("出錯");
                    }

                    @Override
                    public void onComplete() {
                        System.out.println("完成");
                    }
                });
複製程式碼

接下來看圖分析整個流程做了什麼

observeOn

文字分析:和map比較類似的操作,但又有點不同 ①:原始被觀察者呼叫observeOn()的時候,重新建立了一個被觀察者(這裡稱它為observeOn被觀察者),然後用observeOn被觀察者訂閱原始觀察者。 ②:然後訂閱成功後將建立一個觀察者(這裡稱為observeOn觀察者),作為引數呼叫原始被觀察者subscribe(@NonNull ObservableEmitter<Object> e)。 ③:之後的原始被觀察者傳送的onNext事件都會先經過observeOn觀察者onNext事件先,在裡面會進行執行緒的轉換,再呼叫observeOn被觀察者發射器來傳送onNext事件給原始觀察者

observeOn()簡單程式碼如下

public final Observable<T> observeOn(Scheduler scheduler) {
        return Observable.create(new ObservableOnSubscribe<T>() {
            @Override
            public void subscribe(@NonNull Observer<Object> e) {
                 // source為原始被觀察者
                source.subscribe(new Observer<T>() {
                    @Override
                    public void onNext(T var1) {
                        // 執行緒的轉換
                        scheduler.createWorker().schedule(new Runnable() {
                            @Override
                            public void run() {
                                 // e為observeOn被觀察者
                                e.onNext(var1);
                            }
                        });
                    }
                });
            }
        });
    }
複製程式碼

結語

其實RxJava裡面的各種操作符大部分都是利用了這種思想,用各種Observable和Observer來達到目的。 observeOn和subscribeOn對執行緒的排程94這樣,對於裡面什麼方法走在什麼執行緒,應該理解上面所說的就應該清楚了。

感謝:www.jianshu.com/p/88aacbed8…

相關文章