71
RxJava 介紹與 Android 中的 RxJava 千碩 (Kros) oSolve Ltd. / Wish8 Co,. Ltd. Mobile App Developer

Rxjava 介紹與 Android 中的 RxJava

Embed Size (px)

Citation preview

Page 1: Rxjava 介紹與 Android 中的 RxJava

RxJava 介紹與 Android 中的 RxJava

⿈黃千碩 (Kros)oSolve Ltd. / Wish8 Co,. Ltd.

Mobile App Developer

Page 2: Rxjava 介紹與 Android 中的 RxJava

Outline• RxJava Introduction

• Observable

• Operators

• Subject

• Scheduler

• Android Lifecycle

• Testing

• Performance

Page 3: Rxjava 介紹與 Android 中的 RxJava

What is RxJava?

• RxJava 是 Reactive X (Reactive Extensions) 對 Java VM 的實作

• 是⼀一個 Library,利⽤用資料流 (observable sequences) 來處理 「asynchronous 與 event-base 」類型的程式。

• 主要⾓角⾊色為:observable 與 observer 。

Page 4: Rxjava 介紹與 Android 中的 RxJava

What is Reactive?

• 翻譯:「響應式」「反應式」開發

• 把資料 (data) 或是事件 (event) 變成「可觀察」(observer pattern) 的「資料流」。

• 並加上運算元 (operators) 來操作這些資料。

Page 5: Rxjava 介紹與 Android 中的 RxJava

What is FRP ?

• FRP - Functional Reactive Programming.

• Reactive 是⺫⽬目的

• 為了能讓開發者不落⼊入如何處理(事件)資料的繁雜程式邏輯中,利⽤用 函數式 (Functional) 的⽅方法來處理資料流

• filter(), map(), flatMap(), …etc.

Page 6: Rxjava 介紹與 Android 中的 RxJava

Why FRP?• Concurrency

• thread 的控管複雜

• Asynchronous Programming

• 為追求 60fps,許多事情我們會丟到背景處理

• Callback Hell

• 當 Callback 太多時,眼睛都花了。

Page 7: Rxjava 介紹與 Android 中的 RxJava

– 林信良

“若開發者是以務實且不斷提升作為⾃自我期許,更⾼高階的抽象化作法將會是必修的課題”

Page 8: Rxjava 介紹與 Android 中的 RxJava

Observable

• Observable 為發射資料的⼈人

Page 9: Rxjava 介紹與 Android 中的 RxJava

Create Observable

• Observable.just()

• Observable.from()

• …etc.

Page 10: Rxjava 介紹與 Android 中的 RxJava

Observable.just()• 把「資料」轉變成 Observable。

Observable.just("Hello World!")

Page 11: Rxjava 介紹與 Android 中的 RxJava

Observer• Observer 為對這些資料有興趣的⼈人

• 透過 subscribe method 連結 observer 與 observable.

• Observer 透過 subscribe 來監聽⼀一個 Observable.

Page 12: Rxjava 介紹與 Android 中的 RxJava

Subscribe• 連結 observable 與 observer

• 通常必須實作 subscribe 的 interface.

• onNext, onError, onComplete

public final Subscription subscribe(final Action1<? super T> onNext, final Action1<Throwable> onError, final Action0 onComplete) { /* ... */ }

Page 13: Rxjava 介紹與 Android 中的 RxJava

>>>>>>>>>>>>>>>>>>> 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() { } });

Page 14: Rxjava 介紹與 Android 中的 RxJava

>>>>>>>>>>>>>>>>>>> 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

Page 15: Rxjava 介紹與 Android 中的 RxJava

>>>>>>>>>>>>>>>>>>> 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,讓程式碼更簡潔

Page 16: Rxjava 介紹與 Android 中的 RxJava

Observable.from• 把「⼀一包資料」轉變成 Observable。⽽而這個

Observable 每次只發射資料中的單⼀一資料

Observable.from(listOfIntegers)

Page 17: Rxjava 介紹與 Android 中的 RxJava

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); });

Page 18: Rxjava 介紹與 Android 中的 RxJava

“Hot” and “Cold” Observable

• Observable 什麼時候會發射資料呢?

• Hot observable

• 當它⼀一建⽴立時就會發射資料

• Cold observable

• 當有 observer subscribe 時,才會發射資料

Page 19: Rxjava 介紹與 Android 中的 RxJava

Operators• Creating Observables (ex: create, from, just, …)

• Transforming Observables (ex: map, flatMap, …)

• Filtering Observables

• Combining Observables

• Error Handling Operators

• Observable Utility Operators

• ……etc.

Page 20: Rxjava 介紹與 Android 中的 RxJava

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 加⼯工

Page 21: Rxjava 介紹與 Android 中的 RxJava

台北市公廁查詢系統利⽤用台北市政府 Open Data

http://data.taipei/

⺫⽬目的:找尋離我最近的公廁

Page 22: Rxjava 介紹與 Android 中的 RxJava

http://data.taipei/

Page 23: Rxjava 介紹與 Android 中的 RxJava

Callback 版本

Page 24: Rxjava 介紹與 Android 中的 RxJava

// - 跟 Server 抓取公廁資料 @GET("/apiAccess") void listToiletCallback(@Query("rid") String rid, @Query("scope") String scope, @Query("limit") int limit, @Query("offset") int offset, Callback<ApiResponse> callback);

Page 25: Rxjava 介紹與 Android 中的 RxJava

// - 跟 Server 抓取公廁資料 @GET("/apiAccess") void listToiletCallback(@Query("rid") String rid, @Query("scope") String scope, @Query("limit") int limit, @Query("offset") int offset, Callback<ApiResponse> callback);

@Overridepublic void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); progressBar.setVisibility(View.VISIBLE); fetchNearestToilet(); }

Page 26: Rxjava 介紹與 Android 中的 RxJava

// - 跟 Server 抓取公廁資料 @GET("/apiAccess") void listToiletCallback(@Query("rid") String rid, @Query("scope") String scope, @Query("limit") int limit, @Query("offset") int offset, Callback<ApiResponse> callback);

@Overridepublic void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); progressBar.setVisibility(View.VISIBLE); fetchNearestToilet(); }

⺫⽬目的:找出距離我 5 km 以內的公廁,並按照遠近排序

Page 27: Rxjava 介紹與 Android 中的 RxJava

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); } }); }

Page 28: Rxjava 介紹與 Android 中的 RxJava

RxJava 版本

Page 29: Rxjava 介紹與 Android 中的 RxJava

// - 跟 Server 抓取公廁資料 @GET("/apiAccess") Observable<ApiResponse> listToilet(@Query("rid") String rid, @Query("scope") String scope, @Query("limit") int limit, @Query("offset") int offset);

Page 30: Rxjava 介紹與 Android 中的 RxJava

// - 跟 Server 抓取公廁資料 @GET("/apiAccess") Observable<ApiResponse> listToilet(@Query("rid") String rid, @Query("scope") String scope, @Query("limit") int limit, @Query("offset") int offset);

@Overridepublic 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)); } }

Page 31: Rxjava 介紹與 Android 中的 RxJava

// - 跟 Server 抓取公廁資料 @GET("/apiAccess") Observable<ApiResponse> listToilet(@Query("rid") String rid, @Query("scope") String scope, @Query("limit") int limit, @Query("offset") int offset);

@Overridepublic 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)); } }

Page 32: Rxjava 介紹與 Android 中的 RxJava

// - 跟 Server 抓取公廁資料 @GET("/apiAccess") Observable<ApiResponse> listToilet(@Query("rid") String rid, @Query("scope") String scope, @Query("limit") int limit, @Query("offset") int offset);

@Overridepublic 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

Page 33: Rxjava 介紹與 Android 中的 RxJava

// - 跟 Server 抓取公廁資料 @GET("/apiAccess") Observable<ApiResponse> listToilet(@Query("rid") String rid, @Query("scope") String scope, @Query("limit") int limit, @Query("offset") int offset);

@Overridepublic 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));

}

Page 34: Rxjava 介紹與 Android 中的 RxJava

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);

@Overridepublic 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)); } }

Page 35: Rxjava 介紹與 Android 中的 RxJava
Page 36: Rxjava 介紹與 Android 中的 RxJava

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

Page 37: Rxjava 介紹與 Android 中的 RxJava

Subject

• Subject 有很多種:

• AsyncSubject

• BehaviorSubject

• PublishSubject

• ReplaySubject

Page 38: Rxjava 介紹與 Android 中的 RxJava

Publish Subject

• 會發送給每個 observers

• 只會接收到 subscribe 之後的 event

Page 39: Rxjava 介紹與 Android 中的 RxJava

Subject

Page 40: Rxjava 介紹與 Android 中的 RxJava

Activity 1

Subject

Page 41: Rxjava 介紹與 Android 中的 RxJava

Activity 1

Subject

subject.subscribe();

Page 42: Rxjava 介紹與 Android 中的 RxJava

Activity 1

Subject

startActivity();

subject.subscribe();

Page 43: Rxjava 介紹與 Android 中的 RxJava

Activity 1 Activity 2

Subject

startActivity();

subject.subscribe();

Page 44: Rxjava 介紹與 Android 中的 RxJava

Activity 1 Activity 2

Subject

startActivity();

// Do something… subject.onNext(Event); finish();

subject.subscribe();

Page 45: Rxjava 介紹與 Android 中的 RxJava

Activity 1 Activity 2

Subject

startActivity();

subject.subscribe();// Do something… subject.onNext(Event); finish();

Page 46: Rxjava 介紹與 Android 中的 RxJava

Activity 1 Activity 2

Subject

startActivity();

subject.subscribe();// Do something… subject.onNext(Event); finish();

Page 47: Rxjava 介紹與 Android 中的 RxJava

Activity 1 Activity 2

Subject

startActivity();

subject.subscribe();// Do something… subject.onNext(Event); finish();

Page 48: Rxjava 介紹與 Android 中的 RxJava

Activity 1 Activity 2

Subject

startActivity();

subject.subscribe();// Do something… subject.onNext(Event); finish();

Page 49: Rxjava 介紹與 Android 中的 RxJava

Activity 2

Subject

startActivity();

subject.subscribe();// Do something… subject.onNext(Event); finish();

Activity 1 (with Event)

Page 50: Rxjava 介紹與 Android 中的 RxJava

Activity 1 (with Event) Activity 2

Subject

startActivity();

subject.subscribe();// Do something… subject.onNext(Event); finish();

Page 51: Rxjava 介紹與 Android 中的 RxJava

Subject

subject.subscribe();

Activity 1 (with Event)

Page 52: Rxjava 介紹與 Android 中的 RxJava

Subject

subject.subscribe();

Activity 1 (with Event)

Activity 2 (with Event)

Activity 3 (with Event)

subject.subscribe();

subject.subscribe();

可以很多⼈人註冊

Page 53: Rxjava 介紹與 Android 中的 RxJava

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 的切換。

Page 54: Rxjava 介紹與 Android 中的 RxJava

Scheduler

@Overridepublic 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)); } }

Page 55: Rxjava 介紹與 Android 中的 RxJava

Android Lifecycle• Activity 與 Fragment 都有各⾃自的 lifecycle.

• Activity, onCreate(), onResume(), onPause(), onDestory(), ..etc.

• Fragment, onCreate(), onCreateView(), onResume(), onPause(), onDestory(), ..etc

• 如果 Activity/Fragment 被 destroy 時,你的 async task 還沒做完怎麼辦?

Page 56: Rxjava 介紹與 Android 中的 RxJava

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 還沒做完怎麼辦?

Page 57: Rxjava 介紹與 Android 中的 RxJava

Android Lifecycle

• Import RxJava Android 版compile 'io.reactivex:rxandroid:0.25.0'

• 使⽤用 Android 相關的 observable 與 event. rx.android.lifecycle.LifecycleObservable rx.android.lifecycle.LifecycleEvent

Page 58: Rxjava 介紹與 Android 中的 RxJava

@Overrideprotected void onStart() { super.onStart(); lifecycleSubject.onNext(LifecycleEvent.START); } @Overrideprotected void onResume() { super.onResume(); lifecycleSubject.onNext(LifecycleEvent.RESUME); } @Overrideprotected void onPause() { lifecycleSubject.onNext(LifecycleEvent.PAUSE); super.onPause(); } @Overrideprotected void onStop() { lifecycleSubject.onNext(LifecycleEvent.STOP); super.onStop(); } @Overrideprotected void onDestroy() { lifecycleSubject.onNext(LifecycleEvent.DESTROY); super.onDestroy(); }

private final BehaviorSubject<LifecycleEvent> lifecycleSubject = BehaviorSubject.create();

public class BaseActivity extends AppCompatActivity {

}

Page 59: Rxjava 介紹與 Android 中的 RxJava

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 */ }

Page 60: Rxjava 介紹與 Android 中的 RxJava

@Overridepublic 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)); } }

@Overridepublic 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.

Page 61: Rxjava 介紹與 Android 中的 RxJava

@Overridepublic 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)); } }

@Overridepublic 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.

Page 62: Rxjava 介紹與 Android 中的 RxJava

Testing

• 測試容易

• 簡易的⽅方法, toBlocking()

• 正規的⽅方法, TestSubscriber()

Page 63: Rxjava 介紹與 Android 中的 RxJava

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… }

Page 64: Rxjava 介紹與 Android 中的 RxJava

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()); }

Page 65: Rxjava 介紹與 Android 中的 RxJava

Performance

Page 66: Rxjava 介紹與 Android 中的 RxJava

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()); }

Page 67: Rxjava 介紹與 Android 中的 RxJava

不是每個語⾔言的 Rx 版本效能都很好,導⼊入時需注意

例如:ReactiveCocoa

Page 68: Rxjava 介紹與 Android 中的 RxJava

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)); }]; }

Page 69: Rxjava 介紹與 Android 中的 RxJava

優缺點• 優點

• 程式碼清楚,簡潔

• 容易進⾏行 Asynchronous Programming

• 缺點

• 學習成本⾼高(map????, flatMap?????, amb???)

• ⼊入侵式的,所有 API 被迫改成 Observable<T>

Page 70: Rxjava 介紹與 Android 中的 RxJava

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}

Page 71: Rxjava 介紹與 Android 中的 RxJava

Reference• ReactiveX

http://reactivex.io/

• FRP與函數式-林信良 http://www.ithome.com.tw/voice/91328

• RxJava Android Patternshttp://stablekernel.com/blog/replace-asynctask-asynctaskloader-rx-observable-rxjava-android-patterns/

• Architecting Android…The evolutionhttp://fernandocejas.com/2015/07/18/architecting-android-the-evolution/

• Unit Testing RxJava Observableshttps://medium.com/ribot-labs/unit-testing-rxjava-6e9540d4a329

• Demo Projecthttps://github.com/ch8908/rxjava-demo