SlideShare uma empresa Scribd logo
1 de 71
Baixar para ler offline
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) 來處理 「asynchronous 與 event-
base 」類型的程式。
• 主要⾓角⾊色為:observable 與 observer 。
What is Reactive?
• 翻譯:「響應式」「反應式」開發
• 把資料 (data) 或是事件 (event) 變成「可觀察」
(observer pattern) 的「資料流」。
• 並加上運算元 (operators) 來操作這些資料。
What is FRP ?
• FRP - Functional Reactive Programming.
• Reactive 是⺫⽬目的
• 為了能讓開發者不落⼊入如何處理(事件)資料的
繁雜程式邏輯中,利⽤用 函數式 (Functional) 的⽅方
法來處理資料流
• filter(), map(), flatMap(), …etc.
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 Subscription subscribe(final Action1<? super T> onNext,
final Action1<Throwable> onError,
final Action0 onComplete) {
/* ... */
}
>>>>>>>>>>>>>>>>>>> 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() {

}

});
>>>>>>>>>>>>>>>>>>> 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
>>>>>>>>>>>>>>>>>>> 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,讓程式碼更簡潔
Observable.from
• 把「⼀一包資料」轉變成 Observable。⽽而這個
Observable 每次只發射資料中的單⼀一資料
Observable.from(listOfIntegers)
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);

});
“Hot” and “Cold”
Observable
• Observable 什麼時候會發射資料呢?
• Hot observable
• 當它⼀一建⽴立時就會發射資料
• Cold observable
• 當有 observer subscribe 時,才會發射資料
Operators
• Creating Observables (ex: create, from, just, …)
• Transforming Observables (ex: map, flatMap, …)
• Filtering Observables
• Combining Observables
• Error Handling Operators
• Observable Utility Operators
• ……etc.
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 加⼯工
台北市
公廁查詢系統
利⽤用台北市政府 Open Data
http://data.taipei/
⺫⽬目的:找尋離我最近的公廁
http://data.taipei/
Callback 版本
// - 跟 Server 抓取公廁資料
@GET("/apiAccess")

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

@Query("scope") String scope,

@Query("limit") int limit,

@Query("offset") int offset,

Callback<ApiResponse> callback);
// - 跟 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();
}
// - 跟 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 以內的公廁,
並按照遠近排序
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);

}

});

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

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

@Query("scope") String scope, 

@Query("limit") int limit, 

@Query("offset") int offset);
// - 跟 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));
}
}
// - 跟 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));
}
}
// - 跟 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
// - 跟 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));
}
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));

}
}
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
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
(with Event)
Activity 1
(with Event)
Activity 2
Subject
startActivity();
subject.subscribe();
// Do something…
subject.onNext(Event);
finish();
Subject
subject.subscribe();
Activity 1
(with Event)
Subject
subject.subscribe();
Activity 1
(with Event)
Activity 2
(with Event)
Activity 3
(with Event)
subject.subscribe();
subject.subscribe();
可以很多⼈人註冊
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 的切換。
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));

}
}
Android Lifecycle
• Activity 與 Fragment 都有各⾃自的 lifecycle.
• Activity, onCreate(), onResume(), onPause(),
onDestory(), ..etc.
• Fragment, onCreate(), onCreateView(), onResume(),
onPause(), onDestory(), ..etc
• 如果 Activity/Fragment 被 destroy 時,你的 async task
還沒做完怎麼辦?
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
還沒做完怎麼辦?
Android Lifecycle
• Import RxJava Android 版

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

rx.android.lifecycle.LifecycleObservable

rx.android.lifecycle.LifecycleEvent
@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 {
}
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 */
}
@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.
@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.
Testing
• 測試容易
• 簡易的⽅方法, toBlocking()
• 正規的⽅方法, TestSubscriber()
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…
}
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());

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

}
不是每個語⾔言的 Rx 版本效
能都很好,導⼊入時需注意
例如:ReactiveCocoa
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));

}];

}
優缺點
• 優點
• 程式碼清楚,簡潔
• 容易進⾏行 Asynchronous Programming
• 缺點
• 學習成本⾼高(map????, flatMap?????, amb???)
• ⼊入侵式的,所有 API 被迫改成 Observable<T>
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

}
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

Mais conteúdo relacionado

Mais procurados

김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
min woog kim
 

Mais procurados (20)

CI、CD、Automation你還沒準備好!?(Agile Tour Kaohsiung 2017)
CI、CD、Automation你還沒準備好!?(Agile Tour Kaohsiung 2017)CI、CD、Automation你還沒準備好!?(Agile Tour Kaohsiung 2017)
CI、CD、Automation你還沒準備好!?(Agile Tour Kaohsiung 2017)
 
Utilizing kotlin flows in an android application
Utilizing kotlin flows in an android applicationUtilizing kotlin flows in an android application
Utilizing kotlin flows in an android application
 
How I become Go GDE
How I become Go GDEHow I become Go GDE
How I become Go GDE
 
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
김민욱, (달빛조각사) 엘릭서를 이용한 mmorpg 서버 개발, NDC2019
 
Kotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is comingKotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is coming
 
Effective Java and Kotlin
Effective Java and KotlinEffective Java and Kotlin
Effective Java and Kotlin
 
Idiomatic Kotlin
Idiomatic KotlinIdiomatic Kotlin
Idiomatic Kotlin
 
우아한 모노리스
우아한 모노리스우아한 모노리스
우아한 모노리스
 
무정지&무점검 서버 개발과 운영 사례
무정지&무점검 서버 개발과 운영 사례무정지&무점검 서버 개발과 운영 사례
무정지&무점검 서버 개발과 운영 사례
 
The never-ending REST API design debate
The never-ending REST API design debateThe never-ending REST API design debate
The never-ending REST API design debate
 
Introduction to kotlin coroutines
Introduction to kotlin coroutinesIntroduction to kotlin coroutines
Introduction to kotlin coroutines
 
Kotlin Coroutines in Practice @ KotlinConf 2018
Kotlin Coroutines in Practice @ KotlinConf 2018Kotlin Coroutines in Practice @ KotlinConf 2018
Kotlin Coroutines in Practice @ KotlinConf 2018
 
TypeScript: Basic Features and Compilation Guide
TypeScript: Basic Features and Compilation GuideTypeScript: Basic Features and Compilation Guide
TypeScript: Basic Features and Compilation Guide
 
In-depth analysis of Kotlin Flows
In-depth analysis of Kotlin FlowsIn-depth analysis of Kotlin Flows
In-depth analysis of Kotlin Flows
 
C#のキモイ高速プログラミング
C#のキモイ高速プログラミングC#のキモイ高速プログラミング
C#のキモイ高速プログラミング
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
 
Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)Functional Programming Patterns (BuildStuff '14)
Functional Programming Patterns (BuildStuff '14)
 
Rxjs ngvikings
Rxjs ngvikingsRxjs ngvikings
Rxjs ngvikings
 
Infrastructure Deployment with Docker & Ansible
Infrastructure Deployment with Docker & AnsibleInfrastructure Deployment with Docker & Ansible
Infrastructure Deployment with Docker & Ansible
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
 

Semelhante a Rxjava 介紹與 Android 中的 RxJava

Nexthink Library - replacing a ruby on rails application with Scala and Spray
Nexthink Library - replacing a ruby on rails application with Scala and SprayNexthink Library - replacing a ruby on rails application with Scala and Spray
Nexthink Library - replacing a ruby on rails application with Scala and Spray
Matthew Farwell
 

Semelhante a Rxjava 介紹與 Android 中的 RxJava (20)

Building Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJavaBuilding Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJava
 
Rx java in action
Rx java in actionRx java in action
Rx java in action
 
Practical RxJava for Android
Practical RxJava for AndroidPractical RxJava for Android
Practical RxJava for Android
 
Tech Talk #4 : RxJava and Using RxJava in MVP - Dương Văn Tới
Tech Talk #4 : RxJava and Using RxJava in MVP - Dương Văn TớiTech Talk #4 : RxJava and Using RxJava in MVP - Dương Văn Tới
Tech Talk #4 : RxJava and Using RxJava in MVP - Dương Văn Tới
 
Practical RxJava for Android
Practical RxJava for AndroidPractical RxJava for Android
Practical RxJava for Android
 
Reactive Extensions for JavaScript
Reactive Extensions for JavaScriptReactive Extensions for JavaScript
Reactive Extensions for JavaScript
 
GKAC 2015 Apr. - RxAndroid
GKAC 2015 Apr. - RxAndroidGKAC 2015 Apr. - RxAndroid
GKAC 2015 Apr. - RxAndroid
 
Reactive programming on Android
Reactive programming on AndroidReactive programming on Android
Reactive programming on Android
 
RxJava2 Slides
RxJava2 SlidesRxJava2 Slides
RxJava2 Slides
 
Rxjava meetup presentation
Rxjava meetup presentationRxjava meetup presentation
Rxjava meetup presentation
 
Reactive Thinking in Java
Reactive Thinking in JavaReactive Thinking in Java
Reactive Thinking in Java
 
JS everywhere 2011
JS everywhere 2011JS everywhere 2011
JS everywhere 2011
 
Nexthink Library - replacing a ruby on rails application with Scala and Spray
Nexthink Library - replacing a ruby on rails application with Scala and SprayNexthink Library - replacing a ruby on rails application with Scala and Spray
Nexthink Library - replacing a ruby on rails application with Scala and Spray
 
Programming proxies to do what we need so we don't have to talk to the networ...
Programming proxies to do what we need so we don't have to talk to the networ...Programming proxies to do what we need so we don't have to talk to the networ...
Programming proxies to do what we need so we don't have to talk to the networ...
 
Scala.js for large and complex frontend apps
Scala.js for large and complex frontend appsScala.js for large and complex frontend apps
Scala.js for large and complex frontend apps
 
Reactive Functional Programming with Java 8 on Android N
Reactive Functional Programming with Java 8 on Android NReactive Functional Programming with Java 8 on Android N
Reactive Functional Programming with Java 8 on Android N
 
Belfast JUG 23-10-2013
Belfast JUG 23-10-2013Belfast JUG 23-10-2013
Belfast JUG 23-10-2013
 
Intro to RxJava/RxAndroid - GDG Munich Android
Intro to RxJava/RxAndroid - GDG Munich AndroidIntro to RxJava/RxAndroid - GDG Munich Android
Intro to RxJava/RxAndroid - GDG Munich Android
 
JavaScript Fundamentals with Angular and Lodash
JavaScript Fundamentals with Angular and LodashJavaScript Fundamentals with Angular and Lodash
JavaScript Fundamentals with Angular and Lodash
 
RxJS Operators - Real World Use Cases - AngularMix
RxJS Operators - Real World Use Cases - AngularMixRxJS Operators - Real World Use Cases - AngularMix
RxJS Operators - Real World Use Cases - AngularMix
 

Mais de Kros Huang (7)

Kotlin Receiver Types 介紹
Kotlin Receiver Types 介紹Kotlin Receiver Types 介紹
Kotlin Receiver Types 介紹
 
Android MvRx Framework 介紹
Android MvRx Framework 介紹Android MvRx Framework 介紹
Android MvRx Framework 介紹
 
Kotlin Data Model
Kotlin Data ModelKotlin Data Model
Kotlin Data Model
 
Epoxy 介紹
Epoxy 介紹Epoxy 介紹
Epoxy 介紹
 
Fastlane on Android 介紹
Fastlane on Android 介紹Fastlane on Android 介紹
Fastlane on Android 介紹
 
RxJava 2.0 介紹
RxJava 2.0 介紹RxJava 2.0 介紹
RxJava 2.0 介紹
 
Android with dagger_2
Android with dagger_2Android with dagger_2
Android with dagger_2
 

Último

VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
dharasingh5698
 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
ssuser89054b
 
Call Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort ServiceCall Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night StandCall Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
amitlee9823
 
notes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.pptnotes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.ppt
MsecMca
 
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoorTop Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
dharasingh5698
 
Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar ≼🔝 Delhi door step de...
Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar  ≼🔝 Delhi door step de...Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar  ≼🔝 Delhi door step de...
Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar ≼🔝 Delhi door step de...
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 

Último (20)

VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Ankleshwar 7001035870 Whatsapp Number, 24/07 Booking
 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 
Call Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort ServiceCall Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
Call Girls in Ramesh Nagar Delhi 💯 Call Us 🔝9953056974 🔝 Escort Service
 
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night StandCall Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
Call Girls In Bangalore ☎ 7737669865 🥵 Book Your One night Stand
 
UNIT - IV - Air Compressors and its Performance
UNIT - IV - Air Compressors and its PerformanceUNIT - IV - Air Compressors and its Performance
UNIT - IV - Air Compressors and its Performance
 
CCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete Record
CCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete RecordCCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete Record
CCS335 _ Neural Networks and Deep Learning Laboratory_Lab Complete Record
 
Intze Overhead Water Tank Design by Working Stress - IS Method.pdf
Intze Overhead Water Tank  Design by Working Stress - IS Method.pdfIntze Overhead Water Tank  Design by Working Stress - IS Method.pdf
Intze Overhead Water Tank Design by Working Stress - IS Method.pdf
 
Online banking management system project.pdf
Online banking management system project.pdfOnline banking management system project.pdf
Online banking management system project.pdf
 
Intro To Electric Vehicles PDF Notes.pdf
Intro To Electric Vehicles PDF Notes.pdfIntro To Electric Vehicles PDF Notes.pdf
Intro To Electric Vehicles PDF Notes.pdf
 
notes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.pptnotes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.ppt
 
Call Girls Walvekar Nagar Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Walvekar Nagar Call Me 7737669865 Budget Friendly No Advance BookingCall Girls Walvekar Nagar Call Me 7737669865 Budget Friendly No Advance Booking
Call Girls Walvekar Nagar Call Me 7737669865 Budget Friendly No Advance Booking
 
Booking open Available Pune Call Girls Koregaon Park 6297143586 Call Hot Ind...
Booking open Available Pune Call Girls Koregaon Park  6297143586 Call Hot Ind...Booking open Available Pune Call Girls Koregaon Park  6297143586 Call Hot Ind...
Booking open Available Pune Call Girls Koregaon Park 6297143586 Call Hot Ind...
 
Double rodded leveling 1 pdf activity 01
Double rodded leveling 1 pdf activity 01Double rodded leveling 1 pdf activity 01
Double rodded leveling 1 pdf activity 01
 
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced LoadsFEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
FEA Based Level 3 Assessment of Deformed Tanks with Fluid Induced Loads
 
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...Top Rated  Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
Top Rated Pune Call Girls Budhwar Peth ⟟ 6297143586 ⟟ Call Me For Genuine Se...
 
Thermal Engineering Unit - I & II . ppt
Thermal Engineering  Unit - I & II . pptThermal Engineering  Unit - I & II . ppt
Thermal Engineering Unit - I & II . ppt
 
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoorTop Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
Top Rated Call Girls In chittoor 📱 {7001035870} VIP Escorts chittoor
 
Unit 2- Effective stress & Permeability.pdf
Unit 2- Effective stress & Permeability.pdfUnit 2- Effective stress & Permeability.pdf
Unit 2- Effective stress & Permeability.pdf
 
Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar ≼🔝 Delhi door step de...
Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar  ≼🔝 Delhi door step de...Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar  ≼🔝 Delhi door step de...
Call Now ≽ 9953056974 ≼🔝 Call Girls In New Ashok Nagar ≼🔝 Delhi door step de...
 
Work-Permit-Receiver-in-Saudi-Aramco.pptx
Work-Permit-Receiver-in-Saudi-Aramco.pptxWork-Permit-Receiver-in-Saudi-Aramco.pptx
Work-Permit-Receiver-in-Saudi-Aramco.pptx
 

Rxjava 介紹與 Android 中的 RxJava

  • 1. RxJava 介紹與 Android 中的 RxJava ⿈黃千碩 (Kros) oSolve Ltd. / Wish8 Co,. Ltd. Mobile App Developer
  • 2. Outline • RxJava Introduction • Observable • Operators • Subject • Scheduler • Android Lifecycle • Testing • Performance
  • 3. What is RxJava? • RxJava 是 Reactive X (Reactive Extensions) 對 Java VM 的實作 • 是⼀一個 Library,利⽤用資料流 (observable sequences) 來處理 「asynchronous 與 event- base 」類型的程式。 • 主要⾓角⾊色為:observable 與 observer 。
  • 4. What is Reactive? • 翻譯:「響應式」「反應式」開發 • 把資料 (data) 或是事件 (event) 變成「可觀察」 (observer pattern) 的「資料流」。 • 並加上運算元 (operators) 來操作這些資料。
  • 5. What is FRP ? • FRP - Functional Reactive Programming. • Reactive 是⺫⽬目的 • 為了能讓開發者不落⼊入如何處理(事件)資料的 繁雜程式邏輯中,利⽤用 函數式 (Functional) 的⽅方 法來處理資料流 • filter(), map(), flatMap(), …etc.
  • 6. Why FRP? • Concurrency • thread 的控管複雜 • Asynchronous Programming • 為追求 60fps,許多事情我們會丟到背景處理 • Callback Hell • 當 Callback 太多時,眼睛都花了。
  • 9. Create Observable • Observable.just() • Observable.from() • …etc.
  • 11. Observer • Observer 為對這些資料有興趣的⼈人 • 透過 subscribe method 連結 observer 與 observable. • Observer 透過 subscribe 來監聽⼀一個 Observable.
  • 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. >>>>>>>>>>>>>>>>>>> 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. >>>>>>>>>>>>>>>>>>> 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. >>>>>>>>>>>>>>>>>>> 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. Observable.from • 把「⼀一包資料」轉變成 Observable。⽽而這個 Observable 每次只發射資料中的單⼀一資料 Observable.from(listOfIntegers)
  • 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. “Hot” and “Cold” Observable • Observable 什麼時候會發射資料呢? • Hot observable • 當它⼀一建⽴立時就會發射資料 • Cold observable • 當有 observer subscribe 時,才會發射資料
  • 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. 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 加⼯工
  • 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. // - 跟 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. // - 跟 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. 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);
 }
 });
 }
  • 29. // - 跟 Server 抓取公廁資料 @GET("/apiAccess")
 Observable<ApiResponse> listToilet(@Query("rid") String rid, 
 @Query("scope") String scope, 
 @Query("limit") int limit, 
 @Query("offset") int offset);
  • 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. // - 跟 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. // - 跟 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. // - 跟 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. 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.
  • 36. 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
  • 37. Subject • Subject 有很多種: • AsyncSubject • BehaviorSubject • PublishSubject • ReplaySubject
  • 38. Publish Subject • 會發送給每個 observers • 只會接收到 subscribe 之後的 event
  • 43. Activity 1 Activity 2 Subject startActivity(); subject.subscribe();
  • 44. Activity 1 Activity 2 Subject startActivity(); // Do something… subject.onNext(Event); finish(); subject.subscribe();
  • 45. Activity 1 Activity 2 Subject startActivity(); subject.subscribe(); // Do something… subject.onNext(Event); finish();
  • 46. Activity 1 Activity 2 Subject startActivity(); subject.subscribe(); // Do something… subject.onNext(Event); finish();
  • 47. Activity 1 Activity 2 Subject startActivity(); subject.subscribe(); // Do something… subject.onNext(Event); finish();
  • 48. Activity 1 Activity 2 Subject startActivity(); subject.subscribe(); // Do something… subject.onNext(Event); finish();
  • 49. Activity 2 Subject startActivity(); subject.subscribe(); // Do something… subject.onNext(Event); finish(); Activity 1 (with Event)
  • 50. Activity 1 (with Event) Activity 2 Subject startActivity(); subject.subscribe(); // Do something… subject.onNext(Event); finish();
  • 52. Subject subject.subscribe(); Activity 1 (with Event) Activity 2 (with Event) Activity 3 (with Event) subject.subscribe(); subject.subscribe(); 可以很多⼈人註冊
  • 53. 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 的切換。
  • 54. 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));
 } }
  • 55. Android Lifecycle • Activity 與 Fragment 都有各⾃自的 lifecycle. • Activity, onCreate(), onResume(), onPause(), onDestory(), ..etc. • Fragment, onCreate(), onCreateView(), onResume(), onPause(), onDestory(), ..etc • 如果 Activity/Fragment 被 destroy 時,你的 async task 還沒做完怎麼辦?
  • 56. 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 還沒做完怎麼辦?
  • 57. Android Lifecycle • Import RxJava Android 版
 compile 'io.reactivex:rxandroid:0.25.0' • 使⽤用 Android 相關的 observable 與 event.
 rx.android.lifecycle.LifecycleObservable
 rx.android.lifecycle.LifecycleEvent
  • 58. @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 { }
  • 59. 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 */ }
  • 60. @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.
  • 61. @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.
  • 62. Testing • 測試容易 • 簡易的⽅方法, toBlocking() • 正規的⽅方法, TestSubscriber()
  • 63. 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… }
  • 64. 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());
 }
  • 66. 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());
 }
  • 68. 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));
 }];
 }
  • 69. 優缺點 • 優點 • 程式碼清楚,簡潔 • 容易進⾏行 Asynchronous Programming • 缺點 • 學習成本⾼高(map????, flatMap?????, amb???) • ⼊入侵式的,所有 API 被迫改成 Observable<T>
  • 70. 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
 }
  • 71. 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