Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
RxJava 介紹與
Android 中的 RxJava
⿈黃千碩 (Kros)
oSolve Ltd. / Wish8 Co,. Ltd.
Mobile App Developer
Outline
• RxJava Introduction
• Observable
• Operators
• Subject
• Scheduler
• Android Lifecycle
• Testing
• Performance
What is RxJava?
• RxJava 是 Reactive X (Reactive Extensions) 對
Java VM 的實作
• 是⼀一個 Library,利⽤用資料流 (observable
sequences) 來處理...
What is Reactive?
• 翻譯:「響應式」「反應式」開發
• 把資料 (data) 或是事件 (event) 變成「可觀察」
(observer pattern) 的「資料流」。
• 並加上運算元 (operators) 來操作這...
What is FRP ?
• FRP - Functional Reactive Programming.
• Reactive 是⺫⽬目的
• 為了能讓開發者不落⼊入如何處理(事件)資料的
繁雜程式邏輯中,利⽤用 函數式 (Function...
Why FRP?
• Concurrency
• thread 的控管複雜
• Asynchronous Programming
• 為追求 60fps,許多事情我們會丟到背景處理
• Callback Hell
• 當 Callback 太多...
– 林信良
“若開發者是以務實且不斷提升作為⾃自我期許,更
⾼高階的抽象化作法將會是必修的課題”
Observable
• Observable 為發射資料的⼈人
Create Observable
• Observable.just()
• Observable.from()
• …etc.
Observable.just()
• 把「資料」轉變成 Observable。
Observable.just("Hello World!")
Observer
• Observer 為對這些資料有興趣的⼈人
• 透過 subscribe method 連結 observer 與 observable.
• Observer 透過 subscribe 來監聽⼀一個 Observable.
Subscribe
• 連結 observable 與 observer
• 通常必須實作 subscribe 的 interface.
• onNext, onError, onComplete
public final Subscripti...
>>>>>>>>>>>>>>>>>>> s:Hello World!
Observable.just("Hello World!").subscribe(new Action1<String>() {

@Override

public vo...
>>>>>>>>>>>>>>>>>>> s:Hello World!
Observable.just("Hello World!").subscribe(new Action1<String>() {

@Override

public vo...
>>>>>>>>>>>>>>>>>>> s:Hello World!
Observable.just("Hello World!").subscribe(new Action1<String>() {

@Override

public vo...
Observable.from
• 把「⼀一包資料」轉變成 Observable。⽽而這個
Observable 每次只發射資料中的單⼀一資料
Observable.from(listOfIntegers)
Observable.from
>>>>>>>>>>>>>>>>>>> integer:1
>>>>>>>>>>>>>>>>>>> integer:2
>>>>>>>>>>>>>>>>>>> integer:3
>>>>>>>>>>>>>>>>...
“Hot” and “Cold”
Observable
• Observable 什麼時候會發射資料呢?
• Hot observable
• 當它⼀一建⽴立時就會發射資料
• Cold observable
• 當有 observer sub...
Operators
• Creating Observables (ex: create, from, just, …)
• Transforming Observables (ex: map, flatMap, …)
• Filtering O...
Observable.just("Hello World!").map(s -> s + " Android Taipei")

.subscribe(s -> {

System.out.println(">>>>>>>>>>>>>>>>>>...
台北市
公廁查詢系統
利⽤用台北市政府 Open Data
http://data.taipei/
⺫⽬目的:找尋離我最近的公廁
http://data.taipei/
Callback 版本
// - 跟 Server 抓取公廁資料
@GET("/apiAccess")

void listToiletCallback(@Query("rid") String rid, 

@Query("scope") String scope,...
// - 跟 Server 抓取公廁資料
@GET("/apiAccess")

void listToiletCallback(@Query("rid") String rid, 

@Query("scope") String scope,...
// - 跟 Server 抓取公廁資料
@GET("/apiAccess")

void listToiletCallback(@Query("rid") String rid, 

@Query("scope") String scope,...
private void fetchNearestToilet() {

apiService.listToiletCallback(RID, SCOPE, 500, 0, new Callback<ApiResponse>() {

@Ove...
RxJava 版本
// - 跟 Server 抓取公廁資料
@GET("/apiAccess")

Observable<ApiResponse> listToilet(@Query("rid") String rid, 

@Query("scope") St...
// - 跟 Server 抓取公廁資料
@GET("/apiAccess")

Observable<ApiResponse> listToilet(@Query("rid") String rid, 

@Query("scope") St...
// - 跟 Server 抓取公廁資料
@GET("/apiAccess")

Observable<ApiResponse> listToilet(@Query("rid") String rid, 

@Query("scope") St...
// - 跟 Server 抓取公廁資料
@GET("/apiAccess")

Observable<ApiResponse> listToilet(@Query("rid") String rid, 

@Query("scope") St...
// - 跟 Server 抓取公廁資料
@GET("/apiAccess")

Observable<ApiResponse> listToilet(@Query("rid") String rid, 

@Query("scope") St...
private Observable<List<Toilet>> fetchNearestToilet() {

return apiService.listToilet(RID, SCOPE, 500, 0)

.flatMap(respon...
Subject
• 翻譯:主題
• A Subject is a sort of bridge or proxy that is
available in some implementations of
ReactiveX that acts ...
Subject
• Subject 有很多種:
• AsyncSubject
• BehaviorSubject
• PublishSubject
• ReplaySubject
Publish Subject
• 會發送給每個 observers
• 只會接收到 subscribe 之後的 event
Subject
Activity 1
Subject
Activity 1
Subject
subject.subscribe();
Activity 1
Subject
startActivity();
subject.subscribe();
Activity 1 Activity 2
Subject
startActivity();
subject.subscribe();
Activity 1 Activity 2
Subject
startActivity();
// Do something…
subject.onNext(Event);
finish();
subject.subscribe();
Activity 1 Activity 2
Subject
startActivity();
subject.subscribe();
// Do something…
subject.onNext(Event);
finish();
Activity 1 Activity 2
Subject
startActivity();
subject.subscribe();
// Do something…
subject.onNext(Event);
finish();
Activity 1 Activity 2
Subject
startActivity();
subject.subscribe();
// Do something…
subject.onNext(Event);
finish();
Activity 1 Activity 2
Subject
startActivity();
subject.subscribe();
// Do something…
subject.onNext(Event);
finish();
Activity 2
Subject
startActivity();
subject.subscribe();
// Do something…
subject.onNext(Event);
finish();
Activity 1
(wit...
Activity 1
(with Event)
Activity 2
Subject
startActivity();
subject.subscribe();
// Do something…
subject.onNext(Event);
f...
Subject
subject.subscribe();
Activity 1
(with Event)
Subject
subject.subscribe();
Activity 1
(with Event)
Activity 2
(with Event)
Activity 3
(with Event)
subject.subscribe();
...
Scheduler
• If you want to introduce multithreading into
your cascade of Observable operators, you
can do so by instructin...
Scheduler
@Override

public void onViewCreated(View view, Bundle savedInstanceState) {

super.onViewCreated(view, savedIns...
Android Lifecycle
• Activity 與 Fragment 都有各⾃自的 lifecycle.
• Activity, onCreate(), onResume(), onPause(),
onDestory(), ..et...
Android Lifecycle
• 會導致 Memory leak 或是 NPE.
• Activity 與 Fragment 都有各⾃自的 lifecycle.
• Activity, onCreate(), onResume(), on...
Android Lifecycle
• Import RxJava Android 版

compile 'io.reactivex:rxandroid:0.25.0'
• 使⽤用 Android 相關的 observable 與 event....
@Override

protected void onStart() {

super.onStart();

lifecycleSubject.onNext(LifecycleEvent.START);

}



@Override

p...
public class BaseActivity extends AppCompatActivity {
/* reset code */
public Observable<LifecycleEvent> lifecycle() {

re...
@Override

public void onViewCreated(View view, Bundle savedInstanceState) {

super.onViewCreated(view, savedInstanceState...
@Override

public void onViewCreated(View view, Bundle savedInstanceState) {

super.onViewCreated(view, savedInstanceState...
Testing
• 測試容易
• 簡易的⽅方法, toBlocking()
• 正規的⽅方法, TestSubscriber()
public class AccountDaemon {
public Observable<Account> login(final Account account) {

return Observable.just(account).ma...
public void testLogin_empty_email() throws Exception {

Account account = Account.createLoginAccount(null, "password");

t...
Performance
public void testPerformance_rx() {

List<Integer> data = new ArrayList<>();

for (int i = 0; i < 100000; ++i) {

data.add(...
不是每個語⾔言的 Rx 版本效
能都很好,導⼊入時需注意
例如:ReactiveCocoa
RAC-ReactiveCocoa
- (void)testRACPerformance {

NSArray *array = [self getTestArray];

[self measureBlock:^{

RACSequence ...
優缺點
• 優點
• 程式碼清楚,簡潔
• 容易進⾏行 Asynchronous Programming
• 缺點
• 學習成本⾼高(map????, flatMap?????, amb???)
• ⼊入侵式的,所有 API 被迫改成 Obser...
public void fetchUserProfile() {

// code

}



public void fetchFriends() {

// code

}



public void fetchShippingInfo(...
Reference
• ReactiveX

http://reactivex.io/
• FRP與函數式-林信良

http://www.ithome.com.tw/voice/91328
• RxJava Android Patterns
...
Rxjava 介紹與 Android 中的 RxJava
Upcoming SlideShare
Loading in …5
×

Rxjava 介紹與 Android 中的 RxJava

5,432 views

Published on

2015/08/28 在 PicCollage 的 Android Taipei 的分享。
相關程式碼:
https://github.com/ch8908/rxjava-demo

Published in: Engineering
  • Hello! High Quality And Affordable Essays For You. Starting at $4.99 per page - Check our website! https://vk.cc/82gJD2
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Rxjava 介紹與 Android 中的 RxJava

  1. 1. RxJava 介紹與 Android 中的 RxJava ⿈黃千碩 (Kros) oSolve Ltd. / Wish8 Co,. Ltd. Mobile App Developer
  2. 2. Outline • RxJava Introduction • Observable • Operators • Subject • Scheduler • Android Lifecycle • Testing • Performance
  3. 3. What is RxJava? • RxJava 是 Reactive X (Reactive Extensions) 對 Java VM 的實作 • 是⼀一個 Library,利⽤用資料流 (observable sequences) 來處理 「asynchronous 與 event- base 」類型的程式。 • 主要⾓角⾊色為:observable 與 observer 。
  4. 4. What is Reactive? • 翻譯:「響應式」「反應式」開發 • 把資料 (data) 或是事件 (event) 變成「可觀察」 (observer pattern) 的「資料流」。 • 並加上運算元 (operators) 來操作這些資料。
  5. 5. What is FRP ? • FRP - Functional Reactive Programming. • Reactive 是⺫⽬目的 • 為了能讓開發者不落⼊入如何處理(事件)資料的 繁雜程式邏輯中,利⽤用 函數式 (Functional) 的⽅方 法來處理資料流 • filter(), map(), flatMap(), …etc.
  6. 6. Why FRP? • Concurrency • thread 的控管複雜 • Asynchronous Programming • 為追求 60fps,許多事情我們會丟到背景處理 • Callback Hell • 當 Callback 太多時,眼睛都花了。
  7. 7. – 林信良 “若開發者是以務實且不斷提升作為⾃自我期許,更 ⾼高階的抽象化作法將會是必修的課題”
  8. 8. Observable • Observable 為發射資料的⼈人
  9. 9. Create Observable • Observable.just() • Observable.from() • …etc.
  10. 10. Observable.just() • 把「資料」轉變成 Observable。 Observable.just("Hello World!")
  11. 11. Observer • Observer 為對這些資料有興趣的⼈人 • 透過 subscribe method 連結 observer 與 observable. • Observer 透過 subscribe 來監聽⼀一個 Observable.
  12. 12. Subscribe • 連結 observable 與 observer • 通常必須實作 subscribe 的 interface. • onNext, onError, onComplete public final Subscription subscribe(final Action1<? super T> onNext, final Action1<Throwable> onError, final Action0 onComplete) { /* ... */ }
  13. 13. >>>>>>>>>>>>>>>>>>> s:Hello World! Observable.just("Hello World!").subscribe(new Action1<String>() {
 @Override
 public void call(String s) {
 System.out.println(">>>>>>>>>>>>>>>>>>> s:" + s);
 }
 }, new Action1<Throwable>() {
 @Override
 public void call(Throwable throwable) {
 }
 }, new Action0() {
 @Override
 public void call() {
 }
 });
  14. 14. >>>>>>>>>>>>>>>>>>> s:Hello World! Observable.just("Hello World!").subscribe(new Action1<String>() {
 @Override
 public void call(String s) {
 System.out.println(">>>>>>>>>>>>>>>>>>> s:" + s);
 }
 }, new Action1<Throwable>() {
 @Override
 public void call(Throwable throwable) {
 }
 }, new Action0() {
 @Override
 public void call() {
 }
 }); Observable.just("Hello World!").subscribe(new Action1<String>() {
 @Override
 public void call(String s) {
 System.out.println(">>>>>>>>>>>>>>>>>>> s:" + s);
 }
 }); 可以只實作感興趣的 callback
  15. 15. >>>>>>>>>>>>>>>>>>> s:Hello World! Observable.just("Hello World!").subscribe(new Action1<String>() {
 @Override
 public void call(String s) {
 System.out.println(">>>>>>>>>>>>>>>>>>> s:" + s);
 }
 }, new Action1<Throwable>() {
 @Override
 public void call(Throwable throwable) {
 }
 }, new Action0() {
 @Override
 public void call() {
 }
 }); Observable.just("Hello World!").subscribe(new Action1<String>() {
 @Override
 public void call(String s) {
 System.out.println(">>>>>>>>>>>>>>>>>>> s:" + s);
 }
 }); Observable.just("Hello World!").subscribe(s -> {
 System.out.println(">>>>>>>>>>>>>>>>>>> s:" + s);
 }); 套⽤用 retrolambda,採⽤用 java8 lambda,讓程式碼更簡潔
  16. 16. Observable.from • 把「⼀一包資料」轉變成 Observable。⽽而這個 Observable 每次只發射資料中的單⼀一資料 Observable.from(listOfIntegers)
  17. 17. Observable.from >>>>>>>>>>>>>>>>>>> integer:1 >>>>>>>>>>>>>>>>>>> integer:2 >>>>>>>>>>>>>>>>>>> integer:3 >>>>>>>>>>>>>>>>>>> integer:4 >>>>>>>>>>>>>>>>>>> integer:5 >>>>>>>>>>>>>>>>>>> integer:6 >>>>>>>>>>>>>>>>>>> integer:7 List<Integer> integers = new ArrayList<>();
 integers.add(1);
 // ...
 integers.add(7); 
 Observable.from(integers).subscribe(integer -> {
 System.out.println(">>>>>>>>>>>>>>>>>>> integer:" + integer);
 });
  18. 18. “Hot” and “Cold” Observable • Observable 什麼時候會發射資料呢? • Hot observable • 當它⼀一建⽴立時就會發射資料 • Cold observable • 當有 observer subscribe 時,才會發射資料
  19. 19. Operators • Creating Observables (ex: create, from, just, …) • Transforming Observables (ex: map, flatMap, …) • Filtering Observables • Combining Observables • Error Handling Operators • Observable Utility Operators • ……etc.
  20. 20. Observable.just("Hello World!").map(s -> s + " Android Taipei")
 .subscribe(s -> {
 System.out.println(">>>>>>>>>>>>>>>>>>> s:" + s);
 }); Observable.from(integers)
 .map(integer -> integer + 10)
 .subscribe(integer -> {
 System.out.println(">>>>>>>>>>>>>>>>>>> integer:" + integer);
 }); >>>>>>>>>>>>>>>>>>> s:Hello World! Android Taipei >>>>>>>>>>>>>>>>>>> integer:11 >>>>>>>>>>>>>>>>>>> integer:12 >>>>>>>>>>>>>>>>>>> integer:13 >>>>>>>>>>>>>>>>>>> integer:14 >>>>>>>>>>>>>>>>>>> integer:15 >>>>>>>>>>>>>>>>>>> integer:16 >>>>>>>>>>>>>>>>>>> integer:17 對 "Hello World!" 加⼯工 對 list 中每個 element 加⼯工
  21. 21. 台北市 公廁查詢系統 利⽤用台北市政府 Open Data http://data.taipei/ ⺫⽬目的:找尋離我最近的公廁
  22. 22. http://data.taipei/
  23. 23. Callback 版本
  24. 24. // - 跟 Server 抓取公廁資料 @GET("/apiAccess")
 void listToiletCallback(@Query("rid") String rid, 
 @Query("scope") String scope,
 @Query("limit") int limit,
 @Query("offset") int offset,
 Callback<ApiResponse> callback);
  25. 25. // - 跟 Server 抓取公廁資料 @GET("/apiAccess")
 void listToiletCallback(@Query("rid") String rid, 
 @Query("scope") String scope,
 @Query("limit") int limit,
 @Query("offset") int offset,
 Callback<ApiResponse> callback); @Override
 public void onViewCreated(View view, Bundle savedInstanceState) {
 super.onViewCreated(view, savedInstanceState);
 progressBar.setVisibility(View.VISIBLE); fetchNearestToilet(); }
  26. 26. // - 跟 Server 抓取公廁資料 @GET("/apiAccess")
 void listToiletCallback(@Query("rid") String rid, 
 @Query("scope") String scope,
 @Query("limit") int limit,
 @Query("offset") int offset,
 Callback<ApiResponse> callback); @Override
 public void onViewCreated(View view, Bundle savedInstanceState) {
 super.onViewCreated(view, savedInstanceState);
 progressBar.setVisibility(View.VISIBLE); fetchNearestToilet(); } ⺫⽬目的:找出距離我 5 km 以內的公廁, 並按照遠近排序
  27. 27. private void fetchNearestToilet() {
 apiService.listToiletCallback(RID, SCOPE, 500, 0, new Callback<ApiResponse>() {
 @Override
 public void success(ApiResponse apiResponse, Response response) {
 List<Toilet> filtered = new ArrayList<>();
 for (Toilet toilet : apiResponse.getResult().getToilets()) {
 if (lessThan5Km(toilet)) {
 filtered.add(toilet);
 }
 }
 Collections.sort(filtered, new Comparator<Toilet>() {
 @Override
 public int compare(Toilet lhs, Toilet rhs) {
 return compareDistance(lhs, rhs);
 }
 });
 adapter.reset(filtered);
 progressBar.setVisibility(View.GONE);
 }
 
 @Override
 public void failure(RetrofitError error) {
 progressBar.setVisibility(View.GONE);
 ViewHelper.showError(getActivity(), error);
 }
 });
 }
  28. 28. RxJava 版本
  29. 29. // - 跟 Server 抓取公廁資料 @GET("/apiAccess")
 Observable<ApiResponse> listToilet(@Query("rid") String rid, 
 @Query("scope") String scope, 
 @Query("limit") int limit, 
 @Query("offset") int offset);
  30. 30. // - 跟 Server 抓取公廁資料 @GET("/apiAccess")
 Observable<ApiResponse> listToilet(@Query("rid") String rid, 
 @Query("scope") String scope, 
 @Query("limit") int limit, 
 @Query("offset") int offset); @Override
 public void onViewCreated(View view, Bundle savedInstanceState) {
 super.onViewCreated(view, savedInstanceState);
 progressBar.setVisibility(View.VISIBLE);
 fetchNearestToilet()
 .observeOn(AndroidSchedulers.mainThread())
 .finallyDo(() -> progressBar.setVisibility(View.GONE))
 .subscribe((toilets) -> {
 adapter.reset(toilets);
 },
 throwable -> ViewHelper.showError(getActivity(), throwable)); } }
  31. 31. // - 跟 Server 抓取公廁資料 @GET("/apiAccess")
 Observable<ApiResponse> listToilet(@Query("rid") String rid, 
 @Query("scope") String scope, 
 @Query("limit") int limit, 
 @Query("offset") int offset); @Override
 public void onViewCreated(View view, Bundle savedInstanceState) {
 super.onViewCreated(view, savedInstanceState);
 progressBar.setVisibility(View.VISIBLE);
 fetchNearestToilet()
 .observeOn(AndroidSchedulers.mainThread())
 .finallyDo(() -> progressBar.setVisibility(View.GONE))
 .subscribe((toilets) -> {
 adapter.reset(toilets);
 },
 throwable -> ViewHelper.showError(getActivity(), throwable)); } }
  32. 32. // - 跟 Server 抓取公廁資料 @GET("/apiAccess")
 Observable<ApiResponse> listToilet(@Query("rid") String rid, 
 @Query("scope") String scope, 
 @Query("limit") int limit, 
 @Query("offset") int offset); @Override
 public void onViewCreated(View view, Bundle savedInstanceState) {
 super.onViewCreated(view, savedInstanceState);
 progressBar.setVisibility(View.VISIBLE);
 fetchNearestToilet()
 .observeOn(AndroidSchedulers.mainThread())
 .finallyDo(() -> progressBar.setVisibility(View.GONE))
 .subscribe(adapter::reset,
 throwable -> ViewHelper.showError(getActivity(), throwable)); } Java 8 的 method reference
  33. 33. // - 跟 Server 抓取公廁資料 @GET("/apiAccess")
 Observable<ApiResponse> listToilet(@Query("rid") String rid, 
 @Query("scope") String scope, 
 @Query("limit") int limit, 
 @Query("offset") int offset); @Override
 public void onViewCreated(View view, Bundle savedInstanceState) {
 super.onViewCreated(view, savedInstanceState);
 progressBar.setVisibility(View.VISIBLE);
 fetchNearestToilet()
 .observeOn(AndroidSchedulers.mainThread())
 .finallyDo(() -> progressBar.setVisibility(View.GONE))
 .subscribe(adapter::reset,
 throwable -> ViewHelper.showError(getActivity(), throwable)); }
  34. 34. private Observable<List<Toilet>> fetchNearestToilet() {
 return apiService.listToilet(RID, SCOPE, 500, 0)
 .flatMap(response -> Observable.from(response.getResult().getToilets()))
 .filter(this::lessThan5Km)
 .toSortedList(this::compareDistance);
 } // - 跟 Server 抓取公廁資料 @GET("/apiAccess")
 Observable<ApiResponse> listToilet(@Query("rid") String rid, 
 @Query("scope") String scope, 
 @Query("limit") int limit, 
 @Query("offset") int offset); @Override
 public void onViewCreated(View view, Bundle savedInstanceState) {
 super.onViewCreated(view, savedInstanceState);
 progressBar.setVisibility(View.VISIBLE);
 fetchNearestToilet()
 .observeOn(AndroidSchedulers.mainThread())
 .finallyDo(() -> progressBar.setVisibility(View.GONE))
 .subscribe(adapter::reset,
 throwable -> ViewHelper.showError(getActivity(), throwable));
 } }
  35. 35. Subject • 翻譯:主題 • A Subject is a sort of bridge or proxy that is available in some implementations of ReactiveX that acts both as an observer and as an Observable. • Subject 可以是發送 event 的⼈人 (observable), 也可以是註冊 event 的⼈人 (observer)。 • ⽤用途:Event Bus
  36. 36. Subject • Subject 有很多種: • AsyncSubject • BehaviorSubject • PublishSubject • ReplaySubject
  37. 37. Publish Subject • 會發送給每個 observers • 只會接收到 subscribe 之後的 event
  38. 38. Subject
  39. 39. Activity 1 Subject
  40. 40. Activity 1 Subject subject.subscribe();
  41. 41. Activity 1 Subject startActivity(); subject.subscribe();
  42. 42. Activity 1 Activity 2 Subject startActivity(); subject.subscribe();
  43. 43. Activity 1 Activity 2 Subject startActivity(); // Do something… subject.onNext(Event); finish(); subject.subscribe();
  44. 44. Activity 1 Activity 2 Subject startActivity(); subject.subscribe(); // Do something… subject.onNext(Event); finish();
  45. 45. Activity 1 Activity 2 Subject startActivity(); subject.subscribe(); // Do something… subject.onNext(Event); finish();
  46. 46. Activity 1 Activity 2 Subject startActivity(); subject.subscribe(); // Do something… subject.onNext(Event); finish();
  47. 47. Activity 1 Activity 2 Subject startActivity(); subject.subscribe(); // Do something… subject.onNext(Event); finish();
  48. 48. Activity 2 Subject startActivity(); subject.subscribe(); // Do something… subject.onNext(Event); finish(); Activity 1 (with Event)
  49. 49. Activity 1 (with Event) Activity 2 Subject startActivity(); subject.subscribe(); // Do something… subject.onNext(Event); finish();
  50. 50. Subject subject.subscribe(); Activity 1 (with Event)
  51. 51. Subject subject.subscribe(); Activity 1 (with Event) Activity 2 (with Event) Activity 3 (with Event) subject.subscribe(); subject.subscribe(); 可以很多⼈人註冊
  52. 52. Scheduler • If you want to introduce multithreading into your cascade of Observable operators, you can do so by instructing those operators (or particular Observables) to operate on particular Schedulers. • 可以利⽤用 Scheduler 來實作 thread 的切換。
  53. 53. Scheduler @Override
 public void onViewCreated(View view, Bundle savedInstanceState) {
 super.onViewCreated(view, savedInstanceState);
 progressBar.setVisibility(View.VISIBLE);
 fetchNearestToilet()
 .observeOn(AndroidSchedulers.mainThread())
 .finallyDo(() -> progressBar.setVisibility(View.GONE))
 .subscribe(adapter::reset,
 throwable -> ViewHelper.showError(getActivity(), throwable));
 } }
  54. 54. Android Lifecycle • Activity 與 Fragment 都有各⾃自的 lifecycle. • Activity, onCreate(), onResume(), onPause(), onDestory(), ..etc. • Fragment, onCreate(), onCreateView(), onResume(), onPause(), onDestory(), ..etc • 如果 Activity/Fragment 被 destroy 時,你的 async task 還沒做完怎麼辦?
  55. 55. Android Lifecycle • 會導致 Memory leak 或是 NPE. • Activity 與 Fragment 都有各⾃自的 lifecycle. • Activity, onCreate(), onResume(), onPause(), onDestory(), ..etc. • Fragment, onCreate(), onCreateView(), onResume(), onPause(), onDestory(), ..etc • 如果 Activity/Fragment 被 destroy 時,你的 async task 還沒做完怎麼辦?
  56. 56. Android Lifecycle • Import RxJava Android 版
 compile 'io.reactivex:rxandroid:0.25.0' • 使⽤用 Android 相關的 observable 與 event.
 rx.android.lifecycle.LifecycleObservable
 rx.android.lifecycle.LifecycleEvent
  57. 57. @Override
 protected void onStart() {
 super.onStart();
 lifecycleSubject.onNext(LifecycleEvent.START);
 }
 
 @Override
 protected void onResume() {
 super.onResume();
 lifecycleSubject.onNext(LifecycleEvent.RESUME);
 }
 
 @Override
 protected void onPause() {
 lifecycleSubject.onNext(LifecycleEvent.PAUSE);
 super.onPause();
 }
 
 @Override
 protected void onStop() {
 lifecycleSubject.onNext(LifecycleEvent.STOP);
 super.onStop();
 }
 
 @Override
 protected void onDestroy() {
 lifecycleSubject.onNext(LifecycleEvent.DESTROY);
 super.onDestroy();
 } private final BehaviorSubject<LifecycleEvent> lifecycleSubject = BehaviorSubject.create(); public class BaseActivity extends AppCompatActivity { }
  58. 58. public class BaseActivity extends AppCompatActivity { /* reset code */ public Observable<LifecycleEvent> lifecycle() {
 return lifecycleSubject.asObservable();
 } protected <T> Observable<T> bind(Observable<T> observable) {
 return LifecycleObservable.bindActivityLifecycle(lifecycle(),
 observable.observeOn(AndroidSchedulers.mainThread()));
 } /* reset code */ }
  59. 59. @Override
 public void onViewCreated(View view, Bundle savedInstanceState) {
 super.onViewCreated(view, savedInstanceState);
 progressBar.setVisibility(View.VISIBLE);
 bind(fetchNearestToilet())
 .finallyDo(() -> progressBar.setVisibility(View.GONE))
 .subscribe(adapter::reset,
 throwable -> ViewHelper.showError(getActivity(), throwable));
 } } @Override
 public void onViewCreated(View view, Bundle savedInstanceState) {
 super.onViewCreated(view, savedInstanceState);
 progressBar.setVisibility(View.VISIBLE);
 fetchNearestToilet()
 .observeOn(AndroidSchedulers.mainThread())
 .finallyDo(() -> progressBar.setVisibility(View.GONE))
 .subscribe(adapter::reset,
 throwable -> ViewHelper.showError(getActivity(), throwable));
 } } bind() 的功能:當 fragment 被 destroyed 時,會⾃自動 unsubscribe 此 observable.
  60. 60. @Override
 public void onViewCreated(View view, Bundle savedInstanceState) {
 super.onViewCreated(view, savedInstanceState);
 progressBar.setVisibility(View.VISIBLE);
 fetchNearestToilet()
 .observeOn(AndroidSchedulers.mainThread())
 .finallyDo(() -> progressBar.setVisibility(View.GONE))
 .subscribe(adapter::reset,
 throwable -> ViewHelper.showError(getActivity(), throwable));
 } } @Override
 public void onViewCreated(View view, Bundle savedInstanceState) {
 super.onViewCreated(view, savedInstanceState);
 progressBar.setVisibility(View.VISIBLE);
 bind(fetchNearestToilet())
 .finallyDo(() -> progressBar.setVisibility(View.GONE))
 .subscribe(adapter::reset,
 throwable -> ViewHelper.showError(getActivity(), throwable));
 } } bind() 的功能:當 fragment 被 destroyed 時,會⾃自動 unsubscribe 此 observable.
  61. 61. Testing • 測試容易 • 簡易的⽅方法, toBlocking() • 正規的⽅方法, TestSubscriber()
  62. 62. public class AccountDaemon { public Observable<Account> login(final Account account) {
 return Observable.just(account).map(account1 -> {
 checkAccount(account);
 return accountService.login(account);
 });
 } private void checkAccount(Account account) throws IllegalArgumentException {
 if (TextUtils.isEmpty(account.getEmail())
 || TextUtils.isEmpty(account.getPassword())) {
 throw new IllegalArgumentException("Email or password can not be empty.");
 }
 } } public class Account {
 private final String email;
 private final String password;
 public static Account createLoginAccount(final String email, 
 final String password) {
 return new Account(email, password);
 }
 // rest implementation… }
  63. 63. public void testLogin_empty_email() throws Exception {
 Account account = Account.createLoginAccount(null, "password");
 try {
 accountDaemon.login(account).toBlocking().single();
 fail("method should throw exception");
 } catch (Throwable ex) {
 assertEquals("Email or password can not be empty.", ex.getLocalizedMessage());
 }
 } // Official way public void testLogin_using_test_subscriber() {
 TestSubscriber<Account> testSubscriber = new TestSubscriber<>();
 Account account = Account.createLoginAccount("email", "password");
 accountDaemon.login(account).subscribe(testSubscriber);
 
 Account expect = Account.createLoginAccount("email", "password");
 testSubscriber.assertNoErrors();
 testSubscriber.assertValue(expect);
 } // Blocking way public void testLogin() throws Exception {
 Account account = Account.createLoginAccount("email", "password");
 Account result = accountDaemon.login(account).toBlocking().single();
 assertEquals("email", result.getEmail());
 assertEquals("password", result.getPassword());
 }
  64. 64. Performance
  65. 65. public void testPerformance_rx() {
 List<Integer> data = new ArrayList<>();
 for (int i = 0; i < 100000; ++i) {
 data.add(i);
 }
 List<Integer> result = Observable.from(data)
 .filter(integer -> integer % 2 == 0).toList().toBlocking().first();
 assertEquals(100000 / 2, result.size());
 } public void testPerformance_for_loop() {
 List<Integer> data = new ArrayList<>();
 for (int i = 0; i < 100000; ++i) {
 data.add(i);
 }
 List<Integer> result = new ArrayList<>();
 for (int i = 0, size = data.size(); i < size; i++) {
 if (i % 2 == 0) {
 result.add(i);
 }
 }
 assertEquals(100000 / 2, result.size());
 }
  66. 66. 不是每個語⾔言的 Rx 版本效 能都很好,導⼊入時需注意 例如:ReactiveCocoa
  67. 67. RAC-ReactiveCocoa - (void)testRACPerformance {
 NSArray *array = [self getTestArray];
 [self measureBlock:^{
 RACSequence *sequence = [array.rac_sequence filter:^BOOL(NSNumber *number) {
 return number.intValue % 2 == 0;
 }];
 NSArray *results = sequence.array;
 XCTAssertEqualObjects(@(100000 / 2), @(results.count));
 }];
 } - (void)testNativePerformance {
 NSArray *array = [self getTestArray];
 [self measureBlock:^{
 NSMutableArray *results = [NSMutableArray array];
 for (int i = 0; i < array.count; ++i) {
 NSNumber *number = array[i];
 if (number.intValue % 2 == 0) {
 [results addObject:number];
 }
 }
 XCTAssertEqualObjects(@(100000 / 2), @(results.count));
 }];
 }
  68. 68. 優缺點 • 優點 • 程式碼清楚,簡潔 • 容易進⾏行 Asynchronous Programming • 缺點 • 學習成本⾼高(map????, flatMap?????, amb???) • ⼊入侵式的,所有 API 被迫改成 Observable<T>
  69. 69. public void fetchUserProfile() {
 // code
 }
 
 public void fetchFriends() {
 // code
 }
 
 public void fetchShippingInfo() {
 // code
 } public Observable<Profile> fetchUserProfile() {
 // code
 }
 
 public Observable<List<Friend>> fetchFriends() {
 // code
 }
 
 public Observable<ShippingInfo> fetchShippingInfo() {
 // code
 }
  70. 70. Reference • ReactiveX
 http://reactivex.io/ • FRP與函數式-林信良
 http://www.ithome.com.tw/voice/91328 • RxJava Android Patterns
 http://stablekernel.com/blog/replace-asynctask-asynctaskloader-rx- observable-rxjava-android-patterns/ • Architecting Android…The evolution
 http://fernandocejas.com/2015/07/18/architecting-android-the-evolution/ • Unit Testing RxJava Observables
 https://medium.com/ribot-labs/unit-testing-rxjava-6e9540d4a329 • Demo Project
 https://github.com/ch8908/rxjava-demo

×