RxJava 進擊的Rx

Action

先看看

之前使用的代碼如果使用Action來代替Subscriber得到的代碼是這樣的

Observable.just("Hi", "Man")
                .subscribe(new Action1<String>() {
                    @Override
                    public void call(String s) {
                        Log.i(TAG, s);
                    }
                });

我的天吶,舒服多了有沒有!!
這裏寫圖片描述

什麼是Action

Action是RxJava 的一個接口,常用的有Action0和Action1。

Action0: 它只有一個方法 call(),這個方法是無參無返回值的;由於 onCompleted() 方法也是無參無返回值的,因此 Action0 可以被當成一個包裝對象,將 onCompleted() 的內容打包起來將自己作爲一個參數傳入 subscribe() 以實現不完整定義的回調

Ation1:它同樣只有一個方法 call(T param),這個方法也無返回值,但有一個參數;與 Action0 同理,由於 onNext(T obj) 和 onError(Throwable error) 也是單參數無返回值的,因此 Action1 可以將 onNext(obj)和 onError(error) 打包起來傳入 subscribe() 以實現不完整定義的回調

Action的使用

定義三個對象,分別打包onNext(obj)、onError(error) 、onCompleted()

 Observable observable = Observable.just("Hello", "World");
      //處理onNext()中的內容
      Action1<String> onNextAction = new Action1<String>() {
          @Override
          public void call(String s) {
              Log.i(TAG, s);
          }
      };
      //處理onError()中的內容
      Action1<Throwable> onErrorAction = new Action1<Throwable>() {
          @Override
          public void call(Throwable throwable) {

          }
      };
      //處理onCompleted()中的內容
      Action0 onCompletedAction = new Action0() {
          @Override
          public void call() {
              Log.i(TAG, "Completed");

          }
      };

接下來使用subscribe重載的方法

//使用 onNextAction 來定義 onNext()
Observable.just("Hello", "World").subscribe(onNextAction);
//使用 onNextAction 和 onErrorAction 來定義 onNext() 和 onError()
Observable.just("Hello", "World").subscribe(onNextAction, onErrorAction);
//使用 onNextAction、 onErrorAction 和 onCompletedAction 來定義 onNext()、 onError() 和 onCompleted()
Observable.just("Hello", "World").subscribe(onNextAction, onErrorAction, onCompletedAction);

重新寫打印”Hi”, “Man”的方法

Observable.just("Hi","Man").subscribe(new Action1<String>() {
        @Override
        public void call(String s) {
        // TODO Auto-generated method stub
        Log.i(TAG, s);
         }
        });

Scheduler

前言

首先,RxJava得模式大概這樣子:由Observable發起事件,經過中間的處理後由Observer消費。(對RxJava還不瞭解的再去看一遍)

在沒使用Scheduler之前,事件的發起和消費都是在同一個線程中執行,也就是說不使用Scheduler的RxJava是同步的~~~顯然不好吧

介紹

RxJava在不指定線程的情況下,發起時間和消費時間默認使用當前線程。所以之前的做法

Observable.just(student1, student2, student2)
//使用map進行轉換,參數1:轉換前的類型,參數2:轉換後的類型
.map(new Func1<Student, String>() {
@Override
public String call(Student i) {
String name = i.getName();//獲取Student對象中的name
return name;//返回name
}
})
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
nameList.add(s);
}
});

因爲是在主線程中發起的,所以不管中間map的處理還是Action1的執行都是在主線程中進行的。若是map中有耗時的操作,這樣會導致主線程擁塞,這並不是我們想看到的。

Scheduler

Scheduler:線程控制器,可以指定每一段代碼在什麼樣的線程中執行。

    模擬一個需求:新的線程發起事件,在主線程中消費
private void rxJavaTest3() {
Observable.just("Hello", "Word")
.subscribeOn(Schedulers.newThread())//指定 subscribe() 發生在新的線程
.observeOn(AndroidSchedulers.mainThread())// 指定 Subscriber 的回調發生在主線程
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.i(TAG, s);
}
            });

上面用到了subscribeOn(),和observeOn()方法來指定發生的線程和消費的線程。

subscribeOn():指定subscribe() 所發生的線程,即Observable.OnSubscribe 被激活時所處的線程。或者叫做事件產生的線程。

observeOn():指定Subscriber 所運行在的線程。或者叫做事件消費的線程。

常用Scheduler線程

Schedulers.immediate():直接在當前線程運行,相當於不指定線程。這是默認的 Scheduler。

Schedulers.newThread():總是啓用新線程,並在新線程執行操作。

Schedulers.io(): I/O 操作(讀寫文件、讀寫數據庫、網絡信息交互等)所使用的 Scheduler。行爲模式和 newThread() 差不多,區別在於 io() 的內部實現是是用一個無數量上限的線程池,可以重用空閒的線程,因此多數情況下 io() 比 newThread() 更有效率。不要把計算工作放在 io() 中,可以避免創建不必要的線程。

Schedulers.computation():計算所使用的 Scheduler。這個計算指的是 CPU 密集型計算,即不會被 I/O 等操作限制性能的操作,例如圖形的計算。這個 Scheduler 使用的固定的線程池,大小爲 CPU 核數。不要把 I/O 操作放在 computation() 中,否則 I/O 操作的等待時間會浪費 CPU。

AndroidSchedulers.mainThread():它指定的操作將在 Android 主線程運行。

多次切換線程

看完上面的介紹想必對RxJava線程的切換有了一些理解,上面只是對事件的發起和消費制定了線程。

如果中間有map之類的操作呢?是否可以實現發起的線程在新線程中,map的處理在IO線程,最後的消費在主線程中。

Observable.just("Hello", "Wrold")
.subscribeOn(Schedulers.newThread())//指定:在新的線程中發起
.observeOn(Schedulers.io())         //指定:在io線程中處理
.map(new Func1<String, String>() {
@Override
public String call(String s) {
return handleString(s);       //處理數據
}
})
.observeOn(AndroidSchedulers.mainThread())//指定:在主線程中處理
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
show(s);                       //消費事件
}
});

可以看到observeOn()被調用了兩次,分別指定了map的處理的現場和消費事件show(s)的線程。

若將observeOn(AndroidSchedulers.mainThread())去掉會怎麼樣?不爲消費事件show(s)指定線程後,show(s)會在那裏執行?

其實,observeOn() 指定的是它之後的操作所在的線程。也就是說,map的處理和最後的消費事件show(s)都會在io線程中執行。
observeOn()可以多次使用,可以隨意變換線程

Subscription

前言

RxJava如何取消訂閱?

就是它 Subscription

RxJava中有個叫做Subscription的接口,可以用來取消訂閱.

publicinterfaceSubscription{
/**
     * Stops the receipt of notifications on the {@link Subscriber} that was registered when this Subscription
     * was received.
     * <p>
* This allows unregistering an {@link Subscriber} before it has finished receiving all events (i.e. before
     * onCompleted is called).
     */voidunsubscribe();

/**
     * Indicates whether this {@code Subscription} is currently unsubscribed.
     *
     * @return {@code true} if this {@code Subscription} is currently unsubscribed, {@code false} otherwise
     */booleanisUnsubscribed();
}

從上面可以看到,只需要調用unsubscribe就可以取消訂閱,那麼如何得到一個Subscription對象呢?

其實很簡單:
Observable.subscribe()方法可以返回一個Subscription的對象,即我們每次訂閱都會返回.

感覺Subscription就像一個訂單,你下單了就會生成一個訂單,而你也可以用這個訂單取消訂單.

OK,內容其實不多,那麼來練習一下吧.

實戰

Subscription subscription = Observable.just("Hello subscription")
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
System.out.println(s);
}
        });
System.out.println(subscription.isUnsubscribed());
subscription.unsubscribe();
System.out.println(subscription.isUnsubscribed());

在我想來輸出的日誌應該是這樣的:

    Hello subscription
    falsetrue

但是,結果出乎我的意料,我運行之後是這樣的:

    Hello subscription
    truetrue

這是什麼鬼啊這裏寫圖片描述

明明我沒有取消訂閱啊,怎麼就true了呢?去源碼探索了一下發現:

在Observable.subscribe()裏有這麼一段代碼:

if (!(subscriber instanceof SafeSubscriber)) {
// assign to `observer` so we return the protected version
subscriber = new SafeSubscriber<T>(subscriber);
}

它會把我們傳遞的subscriber轉成SafeSubscriber,接下去跟進發現

publicvoidonCompleted() {
if (!done) {
done = true;
        try {
actual.onCompleted();
} catch (Throwable e) {
// we handle here instead of another method so we don't add stacks to the frame// which can prevent it from being able to handle StackOverflow
Exceptions.throwIfFatal(e);
// handle errors if the onCompleted implementation fails, not just if the Observable fails
_onError(e);
} finally {
// auto-unsubscribe
unsubscribe();
}
    }
}

原來它在finally裏自動取消了訂閱!!

那麼讓onCompleted晚點執行就行了:

 Subscription subscription = Observable.just("Hello subscription")
.subscribeOn(Schedulers.newThread())//起線程
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
try {
Thread.sleep(5000);//睡5秒,延遲一下
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(s);
}
            });

//默認subscription 調用完
System.out.println(subscription.isUnsubscribed());
subscription.unsubscribe();
System.out.println(subscription.isUnsubscribed());
    輸出結果:

    falsetrue

好吧,終於對了,明明取消了,就不能有了這纔是正確的嘛。

說點什麼吧

之前說着邊學,就着手來一發Gank.io的妹子App的,現在也抽了時間寫完了:(有緣人來看看,雖然是便宜的滿大街的貨色,但是緣分這種東西誰說的準呢,是吧。)
https://github.com/GitHuborz/MeiZi

基於 Retrofit+RxJava+MVP 模式的一個瀏覽Gank. 妹子的小Demo App 主要用到的是: 黃油刀(butterknife)、glide、cardView、CollapsingToolbarLayout、SwipeWindowHelper(左滑返回)等等。

主要是這些知識,之前一直都是處於聽,和隨便谷歌一下啥的,就知道這麼個東西,可是都沒有實際的應用場合去使用,所以最近趁着時間有點充裕和工作比較輕鬆,

就把這些一一都乘機學了一遍,然後編做筆記,到最後就想到了結合起來弄這麼個小Demo,功能比較簡單,但是很多東西都是新的嘗試,BaseActivity等等編碼習慣

也都用在這上面,後續有學到別的,就繼續加在擴充這吧,然後還有很多Bug,和啥的。

這次的學習計劃,到現在爲止還是很有收穫的,不過很多都是隻學到皮毛,還有待在運用中去踩坑,再填坑。O(∩_∩)O~

RxJava 這個還得要繼續深入,因爲這次使用過程中,就發現,很多概念的東西,真的沒有運用的時候都不知道啥坑,我覺得如果把它使用到淋漓致敬,肯定會很棒。

接下來,計劃就是:RxJava的最常用的操作符學習了。

乾巴爹。

請看下回分解~這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章