SlideShare ist ein Scribd-Unternehmen logo
1 von 71
Downloaden Sie, um offline zu lesen
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

Weitere ähnliche Inhalte

Was ist angesagt?

Functional programming with Java 8
Functional programming with Java 8Functional programming with Java 8
Functional programming with Java 8LivePerson
 
Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2José Paumard
 
Introduction to RxJS
Introduction to RxJSIntroduction to RxJS
Introduction to RxJSBrainhub
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React AlicanteIgnacio Martín
 
Java 8 presentation
Java 8 presentationJava 8 presentation
Java 8 presentationVan Huong
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaWiem Zine Elabidine
 
Coroutines in Kotlin
Coroutines in KotlinCoroutines in Kotlin
Coroutines in KotlinAlexey Soshin
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modelingMario Fusco
 
Angular & RXJS: examples and use cases
Angular & RXJS: examples and use casesAngular & RXJS: examples and use cases
Angular & RXJS: examples and use casesFabio Biondi
 
Spray Json and MongoDB Queries: Insights and Simple Tricks.
Spray Json and MongoDB Queries: Insights and Simple Tricks.Spray Json and MongoDB Queries: Insights and Simple Tricks.
Spray Json and MongoDB Queries: Insights and Simple Tricks.Andrii Lashchenko
 
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 applicationSeven Peaks Speaks
 
RxJS Evolved
RxJS EvolvedRxJS Evolved
RxJS Evolvedtrxcllnt
 
Javascript under the hood 2
Javascript under the hood 2Javascript under the hood 2
Javascript under the hood 2Thang Tran Duc
 
A Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIOA Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIOJorge Vásquez
 
Why functional programming and category theory strongly matters
Why functional programming and category theory strongly mattersWhy functional programming and category theory strongly matters
Why functional programming and category theory strongly mattersPiotr Paradziński
 
PHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object CalisthenicsPHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object CalisthenicsGuilherme Blanco
 
Functional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis AtencioFunctional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis AtencioLuis Atencio
 
Json in Postgres - the Roadmap
 Json in Postgres - the Roadmap Json in Postgres - the Roadmap
Json in Postgres - the RoadmapEDB
 

Was ist angesagt? (20)

Functional programming with Java 8
Functional programming with Java 8Functional programming with Java 8
Functional programming with Java 8
 
Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2Lambdas and Streams Master Class Part 2
Lambdas and Streams Master Class Part 2
 
Monadic Java
Monadic JavaMonadic Java
Monadic Java
 
Introduction to RxJS
Introduction to RxJSIntroduction to RxJS
Introduction to RxJS
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React Alicante
 
Java 8 presentation
Java 8 presentationJava 8 presentation
Java 8 presentation
 
ZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in ScalaZIO: Powerful and Principled Functional Programming in Scala
ZIO: Powerful and Principled Functional Programming in Scala
 
Coroutines in Kotlin
Coroutines in KotlinCoroutines in Kotlin
Coroutines in Kotlin
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
Angular & RXJS: examples and use cases
Angular & RXJS: examples and use casesAngular & RXJS: examples and use cases
Angular & RXJS: examples and use cases
 
Spray Json and MongoDB Queries: Insights and Simple Tricks.
Spray Json and MongoDB Queries: Insights and Simple Tricks.Spray Json and MongoDB Queries: Insights and Simple Tricks.
Spray Json and MongoDB Queries: Insights and Simple Tricks.
 
Introduction to java 8 stream api
Introduction to java 8 stream apiIntroduction to java 8 stream api
Introduction to java 8 stream api
 
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
 
RxJS Evolved
RxJS EvolvedRxJS Evolved
RxJS Evolved
 
Javascript under the hood 2
Javascript under the hood 2Javascript under the hood 2
Javascript under the hood 2
 
A Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIOA Prelude of Purity: Scaling Back ZIO
A Prelude of Purity: Scaling Back ZIO
 
Why functional programming and category theory strongly matters
Why functional programming and category theory strongly mattersWhy functional programming and category theory strongly matters
Why functional programming and category theory strongly matters
 
PHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object CalisthenicsPHP para Adultos: Clean Code e Object Calisthenics
PHP para Adultos: Clean Code e Object Calisthenics
 
Functional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis AtencioFunctional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis Atencio
 
Json in Postgres - the Roadmap
 Json in Postgres - the Roadmap Json in Postgres - the Roadmap
Json in Postgres - the Roadmap
 

Ähnlich wie Rxjava 介紹與 Android 中的 RxJava

Building Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJavaBuilding Scalable Stateless Applications with RxJava
Building Scalable Stateless Applications with RxJavaRick Warren
 
Practical RxJava for Android
Practical RxJava for AndroidPractical RxJava for Android
Practical RxJava for AndroidTomáš Kypta
 
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ớiNexus FrontierTech
 
Practical RxJava for Android
Practical RxJava for AndroidPractical RxJava for Android
Practical RxJava for AndroidTomáš Kypta
 
Reactive Extensions for JavaScript
Reactive Extensions for JavaScriptReactive Extensions for JavaScript
Reactive Extensions for JavaScriptJim Wooley
 
GKAC 2015 Apr. - RxAndroid
GKAC 2015 Apr. - RxAndroidGKAC 2015 Apr. - RxAndroid
GKAC 2015 Apr. - RxAndroidGDG Korea
 
Reactive programming on Android
Reactive programming on AndroidReactive programming on Android
Reactive programming on AndroidTomáš Kypta
 
RxJava2 Slides
RxJava2 SlidesRxJava2 Slides
RxJava2 SlidesYarikS
 
Reactive Thinking in Java
Reactive Thinking in JavaReactive Thinking in Java
Reactive Thinking in JavaYakov Fain
 
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 SprayMatthew Farwell
 
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...Lori MacVittie
 
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 appsOtto Chrons
 
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 NShipeng Xu
 
Belfast JUG 23-10-2013
Belfast JUG 23-10-2013Belfast JUG 23-10-2013
Belfast JUG 23-10-2013eamonnlong
 
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 AndroidEgor Andreevich
 
JavaScript Fundamentals with Angular and Lodash
JavaScript Fundamentals with Angular and LodashJavaScript Fundamentals with Angular and Lodash
JavaScript Fundamentals with Angular and LodashBret Little
 
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 - AngularMixTracy Lee
 

Ähnlich wie 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
 

Mehr von Kros Huang

Android MvRx Framework 介紹
Android MvRx Framework 介紹Android MvRx Framework 介紹
Android MvRx Framework 介紹Kros Huang
 
Kotlin Data Model
Kotlin Data ModelKotlin Data Model
Kotlin Data ModelKros Huang
 
Fastlane on Android 介紹
Fastlane on Android 介紹Fastlane on Android 介紹
Fastlane on Android 介紹Kros Huang
 
RxJava 2.0 介紹
RxJava 2.0 介紹RxJava 2.0 介紹
RxJava 2.0 介紹Kros Huang
 
Android with dagger_2
Android with dagger_2Android with dagger_2
Android with dagger_2Kros Huang
 

Mehr von Kros Huang (6)

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
 

Kürzlich hochgeladen

Hostel management system project report..pdf
Hostel management system project report..pdfHostel management system project report..pdf
Hostel management system project report..pdfKamal Acharya
 
Computer Networks Basics of Network Devices
Computer Networks  Basics of Network DevicesComputer Networks  Basics of Network Devices
Computer Networks Basics of Network DevicesChandrakantDivate1
 
Standard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power PlayStandard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power PlayEpec Engineered Technologies
 
Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...
Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...
Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...Arindam Chakraborty, Ph.D., P.E. (CA, TX)
 
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments""Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"mphochane1998
 
Unleashing the Power of the SORA AI lastest leap
Unleashing the Power of the SORA AI lastest leapUnleashing the Power of the SORA AI lastest leap
Unleashing the Power of the SORA AI lastest leapRishantSharmaFr
 
Generative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPTGenerative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPTbhaskargani46
 
S1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptx
S1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptxS1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptx
S1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptxSCMS School of Architecture
 
Engineering Drawing focus on projection of planes
Engineering Drawing focus on projection of planesEngineering Drawing focus on projection of planes
Engineering Drawing focus on projection of planesRAJNEESHKUMAR341697
 
Thermal Engineering Unit - I & II . ppt
Thermal Engineering  Unit - I & II . pptThermal Engineering  Unit - I & II . ppt
Thermal Engineering Unit - I & II . pptDineshKumar4165
 
Rums floating Omkareshwar FSPV IM_16112021.pdf
Rums floating Omkareshwar FSPV IM_16112021.pdfRums floating Omkareshwar FSPV IM_16112021.pdf
Rums floating Omkareshwar FSPV IM_16112021.pdfsmsksolar
 
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKARHAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKARKOUSTAV SARKAR
 
Hazard Identification (HAZID) vs. Hazard and Operability (HAZOP): A Comparati...
Hazard Identification (HAZID) vs. Hazard and Operability (HAZOP): A Comparati...Hazard Identification (HAZID) vs. Hazard and Operability (HAZOP): A Comparati...
Hazard Identification (HAZID) vs. Hazard and Operability (HAZOP): A Comparati...soginsider
 
Online food ordering system project report.pdf
Online food ordering system project report.pdfOnline food ordering system project report.pdf
Online food ordering system project report.pdfKamal Acharya
 
Double Revolving field theory-how the rotor develops torque
Double Revolving field theory-how the rotor develops torqueDouble Revolving field theory-how the rotor develops torque
Double Revolving field theory-how the rotor develops torqueBhangaleSonal
 
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.pptxJuliansyahHarahap1
 
kiln thermal load.pptx kiln tgermal load
kiln thermal load.pptx kiln tgermal loadkiln thermal load.pptx kiln tgermal load
kiln thermal load.pptx kiln tgermal loadhamedmustafa094
 
scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...HenryBriggs2
 

Kürzlich hochgeladen (20)

Hostel management system project report..pdf
Hostel management system project report..pdfHostel management system project report..pdf
Hostel management system project report..pdf
 
Computer Networks Basics of Network Devices
Computer Networks  Basics of Network DevicesComputer Networks  Basics of Network Devices
Computer Networks Basics of Network Devices
 
Standard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power PlayStandard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power Play
 
Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...
Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...
Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...
 
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments""Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
 
Unleashing the Power of the SORA AI lastest leap
Unleashing the Power of the SORA AI lastest leapUnleashing the Power of the SORA AI lastest leap
Unleashing the Power of the SORA AI lastest leap
 
Generative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPTGenerative AI or GenAI technology based PPT
Generative AI or GenAI technology based PPT
 
S1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptx
S1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptxS1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptx
S1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptx
 
Engineering Drawing focus on projection of planes
Engineering Drawing focus on projection of planesEngineering Drawing focus on projection of planes
Engineering Drawing focus on projection of planes
 
Thermal Engineering Unit - I & II . ppt
Thermal Engineering  Unit - I & II . pptThermal Engineering  Unit - I & II . ppt
Thermal Engineering Unit - I & II . ppt
 
Rums floating Omkareshwar FSPV IM_16112021.pdf
Rums floating Omkareshwar FSPV IM_16112021.pdfRums floating Omkareshwar FSPV IM_16112021.pdf
Rums floating Omkareshwar FSPV IM_16112021.pdf
 
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKARHAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
 
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
 
Hazard Identification (HAZID) vs. Hazard and Operability (HAZOP): A Comparati...
Hazard Identification (HAZID) vs. Hazard and Operability (HAZOP): A Comparati...Hazard Identification (HAZID) vs. Hazard and Operability (HAZOP): A Comparati...
Hazard Identification (HAZID) vs. Hazard and Operability (HAZOP): A Comparati...
 
Online food ordering system project report.pdf
Online food ordering system project report.pdfOnline food ordering system project report.pdf
Online food ordering system project report.pdf
 
Call Girls in South Ex (delhi) call me [🔝9953056974🔝] escort service 24X7
Call Girls in South Ex (delhi) call me [🔝9953056974🔝] escort service 24X7Call Girls in South Ex (delhi) call me [🔝9953056974🔝] escort service 24X7
Call Girls in South Ex (delhi) call me [🔝9953056974🔝] escort service 24X7
 
Double Revolving field theory-how the rotor develops torque
Double Revolving field theory-how the rotor develops torqueDouble Revolving field theory-how the rotor develops torque
Double Revolving field theory-how the rotor develops torque
 
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
 
kiln thermal load.pptx kiln tgermal load
kiln thermal load.pptx kiln tgermal loadkiln thermal load.pptx kiln tgermal load
kiln thermal load.pptx kiln tgermal load
 
scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
scipt v1.pptxcxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...
 

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