learn you some rx for the greater good
TRANSCRIPT
Artur Glier
RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM
✓ Microsoft Reactive Extensions by Erik Meijer
Fast forward
✓ Microsoft Reactive Extensions by Erik Meijer✓ Netflix RxJava & RxJs by Ben Christensen
Fast forward
✓ Microsoft Reactive Extensions by Erik Meijer✓ Netflix RxJava & RxJs by Ben Christensen✓ Github ReactiveCocoa
Fast forward
✓ Microsoft Reactive Extensions by Erik Meijer✓ Netflix RxJava & RxJs by Ben Christensen✓ Github ReactiveCocoa (Think different...)
Fast forward
Some of early adopters
RxJava is all about FRP
✓ Programming with asynchronous data streams
FRP is...
✓ Programming with asynchronous data streams
+✓ Toolbox
FRP is...
✓ Cross platform ;)✓ A fun new tool. “If you only have a hammer -
you tend to see each problem as nail.”✓ Less error prone✓ ! a steep learning curve
FRP is...
@interface RACSignal (Operations)
- (RACSignal *)doNext:(void (^)(id x))block;
- (RACSignal *)doError:(void (^)(NSError *error))block;
- (RACSignal *)doCompleted:(void (^)(void))block;
- (RACSignal *)throttle:(NSTimeInterval)interval;
- (RACSignal *)throttle:(NSTimeInterval)interval valuesPassingTest:(BOOL (^)(id next))predicate;
- (RACSignal *)delay:(NSTimeInterval)interval;
- (RACSignal *)repeat;
- (RACSignal *)initially:(void (^)(void))block;
- (RACSignal *)finally:(void (^)(void))block;
- (RACSignal *)bufferWithTime:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler;
- (RACSignal *)collect;
- (RACSignal *)takeLast:(NSUInteger)count;
- (RACSignal *)combineLatestWith:(RACSignal *)signal;
+ (RACSignal *)combineLatest:(id<NSFastEnumeration>)signals;
+ (RACSignal *)combineLatest:(id<NSFastEnumeration>)signals reduce:(id (^)())reduceBlock;
- (RACSignal *)merge:(RACSignal *)signal;
+ (RACSignal *)merge:(id<NSFastEnumeration>)signals;
- (RACSignal *)flatten:(NSUInteger)maxConcurrent;
...
@end
RxJava is an extension of the observer desing pattern
� It’s pull-based approach and any logic requires the result to be available at execution time
Iterables
� Futures are straight-forward to use for a single level of asynchronous execution
� Conditional asynchronous execution flows become difficult to optimally compose
Futures
� They are easy to use with a single level of asynchronous execution but become unwieldy with nested composition.
Callbacks
� Producer can signal consumer that there is no more data available
� Producer can signal consumer that error has ocurred
Observer Pattern
How do you learn RxJava?
BY example
RxJava is all about FRP
FRP is...✓ Responsive, Reslient,
Elastic, Message Driven “FRP manifesto”
✓ Rx = Observables + LINQ + Schedulers “Microsoft”
✓ Programming paradigm for reactive programming using the building blocks of functional programming “Wikipedia”
✓ … “stackoverflow”
FRP is...✓ Responsive, Reslient,
Elastic, Message Driven “FRP manifesto”
✓ Rx = Observables + LINQ + Schedulers “Microsoft”
✓ Programming paradigm for reactive programming using the building blocks of functional programming “Wikipedia”
✓ … “stackoverflow”
FRP is...✓ Responsive, Reslient,
Elastic, Message Driven “FRP manifesto”
✓ Rx = Observables + LINQ + Schedulers “Microsoft”
✓ Programming paradigm for reactive programming using the building blocks of functional programming “Wikipedia”
✓ … “stackoverflow”
FRP is...✓ Responsive, Reslient,
Elastic, Message Driven “FRP manifesto”
✓ Rx = Observables + LINQ + Schedulers “Microsoft”
✓ Programming paradigm for reactive programming using the building blocks of functional programming “Wikipedia”
✓ … “stackoverflow”
FRP is...✓ Responsive, Reslient,
Elastic, Message Driven “FRP manifesto”
✓ Rx = Observables + LINQ + Schedulers “Microsoft”
✓ Programming paradigm for reactive programming using the building blocks of functional programming “Wikipedia”
✓ … “stackoverflow”
Bla, bla, bla...
Rx.Observable.prototype.flatMapLatest(selector, [thisArg])Projects each element of an observable sequence into a new
sequence of observable sequences by incorporating the element's
index and then transforms an observable sequence of observable
sequences into an observable sequence producing values only from
the most recent observable sequence.
BY example
RxJava is all about marbles
Not this kind of marbles
This kind of marbles
RxJava is all about code
Observable<String> observable = Observable.just("Hello, World!");
Subscriber<String> subscriber = new Subscriber<String>() {
@Override
public void onCompleted() {
// code here
}
@Override
public void onError(Throwable e) {
// code here
}
@Override
public void onNext(String s) {
output.append(String.format("%s\n", s));
}
};
@Override
protected void onStart() {
super.onStart();
observable
.observeOn(Schedulers.newThread())
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
Request compositionpublic interface AftonbladetAPI {
@GET("/item/{id}.json")
Observable<Item> item(@Path("id") long id);
@GET("/topstories.json")
Observable<List<Long>> topStories();
}
Request compositionGET /topstories
[ 8414149, 8414078, 8413972, 8411638, 8414102, 8413204, 8413100, 8413971,
8412744, 8414003, 8412841, 8412802, 8412605, 8413548, 8413123, 8414437,
8412897, 8413028, 8413341, 8412425, 8411762, 8413623, 8412346, 8411356,
8413056, 8413365, 8412372, 8414055, 8412877, 8412167, 8413264, 8414137,
8410519, 8412933, 8411846, 8412929, 8411254, 8411512, 8412777, 8412626,
8413274, 8414389, 8414117, 8412114, 8412212, 8412759, 8412696, 8412768,
8411643, 8411866, 8413966, 8410976, 8410545, 8410358, 8413979, 8414129,
8411791, 8409075, 8410314, 8411532, 8411553, 8412099, 8412085, 8410356,
8409084, 8412862, 8409823, 8412705, 8410220, 8409323, 8414090, 8410326 ]
Request compositionGET item/8863.json{
"by": "Daniel Söderbäck",
"id": 1,
"score": 111,
"time": 1415793648,
"title": "Swede Jacobson won the Poker World Championships",
"type": "story",
"url": "http://www.aftonbladet.se/sportbladet/poker/article19844615.ab"
}
Request compositionpublic void onRefresh() {
Aftonbladet.API.topStories()
.flatMap(longs -> Observable.from(longs))
.flatMap(id -> Aftonbladet.API.item(id))
.collect(new ArrayList<Item>(), (items, item) -> items.add(item))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(...);
}
Request composition - flatMap()public void onRefresh() {
Aftonbladet.API.topStories()
.flatMap(longs -> Observable.from(longs))
.flatMap(id -> Aftonbladet.API.item(id))
.collect(new ArrayList<Item>(), (items, item) -> items.add(item))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(...);
}
Request composition - flatMap()public void onRefresh() {
Aftonbladet.API.topStories()
.flatMap(longs -> Observable.from(longs))
.flatMap(id -> Aftonbladet.API.item(id))
.collect(new ArrayList<Item>(), (items, item) -> items.add(item))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(...);
}
Request composition - collect()public void onRefresh() {
Aftonbladet.API.topStories()
.flatMap(longs -> Observable.from(longs))
.flatMap(id -> Aftonbladet.API.item(id))
.collect(new ArrayList<Item>(), (items, item) -> items.add(item))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(...);
}
Request composition - threadspublic void onRefresh() {
Aftonbladet.API.topStories()
.flatMap(longs -> Observable.from(longs))
.flatMap(id -> Aftonbladet.API.item(id))
.collect(new ArrayList<Item>(), (items, item) -> items.add(item))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(...);
}
Request compositionpublic void onRefresh() {
Aftonbladet.API.topStories()
.flatMap(longs -> Observable.from(longs))
.flatMap(id -> Aftonbladet.API.item(id))
.collect(new ArrayList<Item>(), (items, item) -> items.add(item))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(...);
}
Request composition.subscribe(
items -> list.setAdapter(new ArrayAdapter<Item>(..., ..., items)),
error -> handleError(error),
() -> {
if (ptr.isRefreshing()) ptr.setRefreshing(false);
}
)
Request composition - filter()public void onRefresh() {
HackerNews.API.topStories()
.flatMap(longs -> Observable.from(longs))
.flatMap(id -> HackerNews.API.item(id))
.filter(item -> item.time > 1412985600)
.collect(new ArrayList<Item>(), (items, item) -> items.add(item))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(...);
}
Request composition - limit()public void onRefresh() {
HackerNews.API.topStories()
.flatMap(longs -> Observable.from(longs))
.flatMap(id -> HackerNews.API.item(id))
.filter(item -> item.time > 1412985600)
.limit(10)
.collect(new ArrayList<Item>(), (items, item) -> items.add(item))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(...);
}
Request compositionObservable.zip(
service.getUserPhoto(id),
service.getPhotoMetadata(id),
(photo, metadata) -> createPhotoWithData(photo, metadata))
.subscribe(photoWithData -> showPhoto(photoWithData));
public static Observable<String> getRegIdObservable(final Context context) {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
try {
subscriber.onNext(getDeviceRegId(context));
subscriber.onCompleted();
} catch (Exception e) {
subscriber.onError(e);
}
}
});
}
GcmUtils.getRegIdObservable(this)
.subscribeOn(Schedulers.newThread())
.observeOn(Schedulers.newThread())
.subscribe(new Action1<Topic>() {
@Override
public void call(Topic topic) {
API.subscribeToTopic(/* ... */);
}
});
RxJava is all about fun
✓ https://gist.github.com/vizZ/9756d2e2450a7ef9f744
Any advice?
Questions?
Refactoring Android to RxJava