The document introduces RxJava and how it can be used in Android applications, describing key concepts like Observables, Observers, Operators, and Subjects that allow asynchronous and event-based code to be written in a reactive style. It provides examples of how RxJava can be used to fetch toilet data from an API and handle the asynchronous response more declaratively compared to using callbacks. The document also discusses how subjects can act as both observables that emit events and observers that receive events, making them useful for building event buses between activities.
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
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 的切換。
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());
}