By: Farzad Tabashir
Video Lecture: https://www.youtube.com/watch?v=BH9Rb-FeDE0&list=PLT2xIm2X7W7gq_fD5HMWca1rWQQFeETK-
Declarative programming
what the program must accomplish
rather than describe how to accomplish it as a sequence of the programming language primitives
Declarative Programming |
Impretavie Programming Language (Java) |
Assembly |
Binary Codes |
Hardware |
wikipedia: data flows and propagation of change
simple: pushing data instead of pulling it
implement reactive programming paradigm over sequence of data
Java, Scala, C#, C++, Clojure, JavaScript, Python, Groovy, JRuby, and others
is a JVM library which
implements reactive programming
in a declarative approach
with a functional style
Short answer:
If your program is like most though,
you need to combine events (asynchronous responses from functions/network calls)
have conditional logic interacting between them
and must handle failure scenarios and resource cleanup on any and all of them
This is where the reactive-imperative approach begins to dramatically increase in complexity and reactive-functional programming begins to shine
Central to RxJava is the Observable type
“asynchronous/push ‘dual' to the synchronous/pull Iterable.”
By “dual,” we mean the Observable provides all the functionality of an Iterable except in the reverse flow of data: it is push instead of pull
interface Observable<T> {
Subscription subscribe(Observer s)
}
interface Observer<T> {
void onNext(T t)
void onError(Throwable t)
void onCompleted()
}
for (Story story : stories) {
Log.i(TAG, story.getTitle());
}
//This is equivalent to the following:
for (Iterator<Story> iterator = stories.iterator(); iterator.hasNext();) {
Story story = iterator.next();
Log.i(TAG, story.getTitle());
}
Pull (Iterable) | Push (Observable) |
---|---|
T next() | onNext(T) |
throws Exception | onError(Throwable) |
returns | onCompleted() |
// Iterable<String> as Stream<String>
// that contains 75 strings
getDataFromLocalMemorySynchronously()
.skip(10)
.limit(5)
.map(s -> s + "_transformed")
.forEach(System.out::println)
// Observable<String>
// that emits 75 strings
getDataFromNetworkAsynchronously()
.skip(10)
.take(5)
.map(s -> s + "_transformed")
.subscribe(System.out::println)
Most of these operators are synchronous, meaning that they perform their computation synchronously inside the onNext() as the events pass by.
A single Observable stream is always serialized, but each Observable stream can operate independently of one another, and thus concurrently and/or in parallel.
subscribeOn(Scheduler)
observeOn(Scheduler)
subscribeOn(Scheduler)
multiple calls useless
only the first call works
for all operators
observeOn(Scheduler)
can be called multiple times
changes scheduler downstream
All slow events appearing before the first fast event are silently dropped because there is nothing with which to combine them.
(throtleWithTimeout)
doOnNext()
doOnError()
doOnCompleted()
doOnSubscribe()
doOnUnsubscribe()
...
apiEndpoint.login()
.doOnNext(accessToken ->
storeCredentials(accessToken))
.flatMap(accessToken ->
serviceEndpoint.getUser())
.flatMap( user ->
serviceEndpoint.getUserContact(user.getId() ) )
Typical non-reactive app
Reactive app
More specifically, it provides a Scheduler that schedules on the main thread or any given Looper
Observable.just("one", "two", "three", "four", "five")
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(/* an Observer */);
RxTextView.textChanges(searchTextView)
.filter( s -> s.length() > 2 )
.debounce(100, TimeUnit.MILLISECONDS)
.flatMap( s -> makeApiCall(s) )
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(/* attach observer */);
@POST("User/SignIn")
@FormUrlEncoded
Observable<LoginResponseModel> login(
@Field("username") String username,
@Field("password") String password,
);
CompositeDisposable compositeDisposable =
new CompositeDisposable();
compositeDisposable.add(
observable1.subscribe()
);
compositeDisposable.add(
observable2.subscribe()
);
// onPause, onStop
compositeDisposable.dispose();
run their sequence when and if they are subscribed to
class MySubscriber extends Subscriber<T> {
@Override
public void onStart() {
request(1);
}
@Override
public void onCompleted() {
...
}
@Override
public void onError(Throwable e) {
...
}
@Override
public void onNext(T n) {
...
request(1);
}
}