一桂躏、RxJava概念:
1抢埋、RxJava 有四個基本概念:Observable (可觀察者宋渔,即被觀察者)州疾、 Observer (觀察者)、 subscribe (訂閱)皇拣、事件严蓖。Observable 和 Observer 通過 subscribe() 方法實現(xiàn)訂閱關(guān)系,從而 Observable 可以在需要的時候發(fā)出事件來通知 Observer氧急。
onCompleted(): 事件隊列完結(jié)颗胡。RxJava 不僅把每個事件單獨處理,還會把它們看做一個隊列吩坝。RxJava 規(guī)定毒姨,當不會再有新的 onNext() 發(fā)出時,需要觸發(fā) onCompleted() 方法作為標志钉寝。
onError(): 事件隊列異常弧呐。在事件處理過程中出異常時闸迷,onError() 會被觸發(fā),同時隊列自動終止俘枫,不允許再有事件發(fā)出腥沽。
在一個正確運行的事件序列中, onCompleted() 和 onError() 有且只有一個,并且是事件序列中的最后一個崩哩。需要注意的是巡球,onCompleted() 和 onError() 二者也是互斥的,即在隊列中調(diào)用了其中一個邓嘹,就不應(yīng)該再調(diào)用另一個酣栈。
2、創(chuàng)建 Observer
Subscriber<String> subscriber = new Subscriber<String>() {
? ? @Override
? ? public void onNext(String s) {
? ? ? ? Log.d(tag, "Item: " + s);
? ? }
? ? @Override
? ? public void onCompleted() {
? ? ? ? Log.d(tag, "Completed!");
? ? }
? ? @Override
? ? public void onError(Throwable e) {
? ? ? ? Log.d(tag, "Error!");
? ? }
};
Observer是一個接口汹押,Subscriber是一個抽象類矿筝,Subscriber實現(xiàn)自O(shè)bserver,選擇 Observer 和 Subscriber 是完全一樣的棚贾,區(qū)別在于:
①:onStart():Subscriber中多了個onStart()方法,可以做一些準備工作窖维,他是在Subscribe所發(fā)生的線程被調(diào)用,而不能指定線程妙痹,要在指定的線程來做準備工作铸史,可以使用doOnSubscribe()方法。
②:unsubscribe():這是Subscriber實現(xiàn)另一個接口Subscription中的方法怯伊,用于取消訂閱琳轿。這個方法調(diào)用后,將不再接收事件耿芹,調(diào)用前先isUnsubscribed()判斷狀態(tài)崭篡。在Subscribe()之后,Observable會持有Subscriber的引用吧秕,避免內(nèi)存泄漏的發(fā)生琉闪,調(diào)用unsubscribe()來解除引用關(guān)系。
3砸彬、創(chuàng)建Observable
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
? ? @Override
? ? public void call(Subscriber<? super String> subscriber) {
? ? ? ? subscriber.onNext("Hello");
? ? ? ? subscriber.onNext("Hi");
? ? ? ? subscriber.onNext("Aloha");
? ? ? ? subscriber.onCompleted();
? ? }
});
create() 方法是 RxJava 最基本的創(chuàng)造事件序列的方法颠毙。基于這個方法砂碉, RxJava 還提供了一些方法用來快捷創(chuàng)建事件隊列蛀蜜,例如:
①:just(T...): 將傳入的參數(shù)依次發(fā)送出來。
Observable observable = Observable.just("Hello", "Hi", "Aloha");
②:from(T[]) / from(Iterable<? extends T>) :
將傳入的數(shù)組或 Iterable 拆分成具體對象后绽淘,依次發(fā)送出來。
String[] words = {"Hello", "Hi", "Aloha"};
Observable observable = Observable.from(words);
上面 just(T...) 的例子和 from(T[]) 的例子闹伪,都和之前的 create(OnSubscribe) 的例子是等價的沪铭。
4壮池、Subscribe (訂閱)
observable.subscribe(observer);
// 或者:
observable.subscribe(subscriber);
5、不完整定義的回調(diào)
Action1<String> onNextAction = new Action1<String>() {
? ? // onNext()
? ? @Override
? ? public void call(String s) {
? ? ? ? Log.d(tag, s);
? ? }
};
Action1<Throwable> onErrorAction = new Action1<Throwable>() {
? ? // onError()
? ? @Override
? ? public void call(Throwable throwable) {
? ? ? ? // Error handling
? ? }
};
Action0 onCompletedAction = new Action0() {
? ? // onCompleted()
? ? @Override
? ? public void call() {
? ? ? ? Log.d(tag, "completed");
? ? }
};
// 自動創(chuàng)建 Subscriber 杀怠,并使用 onNextAction 來定義 onNext()
observable.subscribe(onNextAction);
// 自動創(chuàng)建 Subscriber 椰憋,并使用 onNextAction 和 onErrorAction 來定義 onNext() 和 onError()
observable.subscribe(onNextAction, onErrorAction);
// 自動創(chuàng)建 Subscriber ,并使用 onNextAction赔退、 onErrorAction 和 onCompletedAction 來定義 onNext()橙依、 onError() 和 onCompleted()
observable.subscribe(onNextAction, onErrorAction, onCompletedAction);
說明:
Action0 是 RxJava 的一個接口,它只有一個方法 call()硕旗,這個方法是無參無返回值的
Action1 也是一個接口窗骑,它同樣只有一個方法 call(T param),這個方法也無返回值漆枚,但有一個參數(shù)创译;
6、應(yīng)用場景
①:將字符串數(shù)組 names 中的所有字符串依次打印出來
String[] arr = {"小明","小紅","小花"};
Observable.from(arr).subscribe(new Action1<String>() {
? ? @Override
? ? public void call(String s) {
? ? Log.d("SDK","看看哪里調(diào)用了==="+s);
? ? }
});
②:由 id 取得圖片并顯示
int drawableRes = ...;
ImageView imageView = ...;
Observable.create(new OnSubscribe<Drawable>() {
? ? @Override
? ? public void call(Subscriber<? super Drawable> subscriber) {
? ? ? ? Drawable drawable = getTheme().getDrawable(drawableRes));
? ? ? ? subscriber.onNext(drawable);
? ? ? ? subscriber.onCompleted();
? ? }
}).subscribe(new Observer<Drawable>() {
? ? @Override
? ? public void onNext(Drawable drawable) {
? ? ? ? imageView.setImageDrawable(drawable);
? ? }
? ? @Override
? ? public void onCompleted() {
? ? }
? ? @Override
? ? public void onError(Throwable e) {
? ? ? ? Toast.makeText(activity, "Error!", Toast.LENGTH_SHORT).show();
? ? }
});
二墙基、線程控制--Scheduler(調(diào)度器)
1软族、Scheduler的api
①:Schedulers.immediate(): 直接在當前線程運行,相當于不指定線程残制。這是默認的 Scheduler立砸。
②:Schedulers.newThread(): 總是啟用新線程,并在新線程執(zhí)行操作初茶。
③:Schedulers.io(): I/O 操作(讀寫文件颗祝、讀寫數(shù)據(jù)庫、網(wǎng)絡(luò)信息交互等)所使用的 Scheduler纺蛆。行為模式和 newThread() 差不多吐葵,區(qū)別在于 io() 的內(nèi)部實現(xiàn)是是用一個無數(shù)量上限的線程池,可以重用空閑的線程桥氏,因此多數(shù)情況下 io() 比 newThread() 更有效率温峭。不要把計算工作放在 io() 中,可以避免創(chuàng)建不必要的線程字支。
④:Schedulers.computation(): 計算所使用的 Scheduler凤藏。這個計算指的是 CPU 密集型計算,即不會被 I/O 等操作限制性能的操作堕伪,例如圖形的計算揖庄。這個 Scheduler 使用的固定的線程池,大小為 CPU 核數(shù)欠雌。不要把 I/O 操作放在 computation() 中蹄梢,否則 I/O 操作的等待時間會浪費 CPU。
⑤:另外富俄, Android 還有一個專用的 AndroidSchedulers.mainThread()禁炒,它指定的操作將在 Android 主線程運行而咆。
⑥:subscribeOn() 事件產(chǎn)生的線程
⑦:observeOn() 事件消費的線程
三、使用
①:map()? 事件對象的直接變換幕袱,一對一的轉(zhuǎn)化
Observable.just("images/logo.png") // 輸入類型 String
? ? .map(new Func1<String, Bitmap>() {
? ? ? ? @Override
? ? ? ? public Bitmap call(String filePath) { // 參數(shù)類型 String
? ? ? ? ? ? return getBitmapFromPath(filePath); // 返回類型 Bitmap
? ? ? ? }
? ? })
? ? .subscribe(new Action1<Bitmap>() {
? ? ? ? @Override
? ? ? ? public void call(Bitmap bitmap) { // 參數(shù)類型 Bitmap
? ? ? ? ? ? showBitmap(bitmap);
? ? ? ? }
? ? });
FuncX 和 ActionX 的區(qū)別在 FuncX 包裝的是有返回值的方法暴备。
②:flatMap()? ? 一對多得轉(zhuǎn)化
場景:有個學生數(shù)組,打印出每個學生的中的所有課程
Student[] students = ...;
Subscriber<Course> subscriber = new Subscriber<Course>() {
? ? @Override
? ? public void onNext(Course course) {
? ? ? ? Log.d(tag, course.getName());
? ? }
? ? ...
};
Observable.from(students)
? ? .flatMap(new Func1<Student, Observable<Course>>() {
? ? ? ? @Override
? ? ? ? public Observable<Course> call(Student student) {
? ? ? ? ? ? return Observable.from(student.getCourses());
? ? ? ? }
? ? })
? ? .subscribe(subscriber);
③:doOnSubscribe()
Observable.create(onSubscribe)
? ? .subscribeOn(Schedulers.io())
? ? .doOnSubscribe(new Action0() {
? ? ? ? @Override
? ? ? ? public void call() {
? ? ? ? ? ? progressBar.setVisibility(View.VISIBLE); // 需要在主線程執(zhí)行
? ? ? ? }
? ? })
? ? .subscribeOn(AndroidSchedulers.mainThread()) // 指定主線程
? ? .observeOn(AndroidSchedulers.mainThread())
? ? .subscribe(subscriber);
在 doOnSubscribe()的后面跟一個 subscribeOn() 们豌,就能指定準備工作的線程了涯捻。
四、?使用場景
1望迎、 與 Retrofit 的結(jié)合
①:在操作User實體之前障癌,需要拿User進行比對數(shù)據(jù)
@GET("/user")
public Observable<User> getUser(@Query("userId") String userId);
getUser(userId)
? ? .doOnNext(new Action1<User>() {
? ? ? ? @Override
? ? ? ? public void call(User user) {
? ? ? ? ? ? processUser(user);
? ? ? ? })
? ? .observeOn(AndroidSchedulers.mainThread())
? ? .subscribe(new Observer<User>() {
? ? ? ? @Override
? ? ? ? public void onNext(User user) {
? ? ? ? ? ? userView.setUser(user);
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void onCompleted() {
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void onError(Throwable error) {
? ? ? ? ? ? // Error handling
? ? ? ? ? ? ...
? ? ? ? }
? ? });
②:假設(shè) /user 接口并不能直接訪問,而需要填入一個在線獲取的 token
@GET("/token")
public Observable<String> getToken();
@GET("/user")
public Observable<User> getUser(@Query("token") String token, @Query("userId") String userId);
...
getToken()
? ? .flatMap(new Func1<String, Observable<User>>() {
? ? ? ? @Override
? ? ? ? public Observable<User> onNext(String token) {
? ? ? ? ? ? return getUser(token, userId);
? ? ? ? })
? ? .observeOn(AndroidSchedulers.mainThread())
? ? .subscribe(new Observer<User>() {
? ? ? ? @Override
? ? ? ? public void onNext(User user) {
? ? ? ? ? ? userView.setUser(user);
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void onCompleted() {
? ? ? ? }
? ? ? ? @Override
? ? ? ? public void onError(Throwable error) {
? ? ? ? ? ? // Error handling
? ? ? ? ? ? ...
? ? ? ? }
? ? });