Android Application Architecture with RxJava

by Predko Silvestr

GDG Ternopil

Content

  • Reactive programming

  • Why I need Rx?

  • RxJava and RxAndroid

  • RxLifecycle

  • Retrofit 2.0, Realm

  • Design app architecture

What about streams?

Reactive Programming

Reactive programming built on strems

For Example:

b = 4;
c = 6;

a = b + c; // a = 10
b = 10; // a = 16
c = 7; // a = 17
Imperative
Reactive
b = 4;
c = 6;

a = b + c; // a = 10
b = 10; // a = 10
c = 7; // a = 10
vs

Why I need Rx?

  • For executing code in background

  • For code simplicity

  • For error handling

  • For scalable app architecture

Android Async Tools

RxJava and RxAndroid

RxJava is a combination of the best ideas from

the Observer and Iterator pattern

The Basics

The basic building blocks of reactive code are Observables and Subscribers

An Observable emits items; a Subscriber consumes those items.

Hello World!

Observable<String> myObservable = Observable.create(
    new Observable.OnSubscribe<String>() {
        @Override
        public void call(Subscriber<? super String> sub) {
            sub.onNext("Hello world!");
            sub.onCompleted();
        }
    }
);

myObservable.subscribe(mySubscriber);
Subscriber<String> mySubscriber = new Subscriber<String>() {
    @Override
    public void onNext(String s) { System.out.println(s); }

    @Override
    public void onCompleted() { }

    @Override
    public void onError(Throwable e) { }
};
            it's the same as sub.onComplete, but also throw exception.
sub.onError(Throwable e)

Text

Creating Observables

Observable.create(onSubscribe); 
// accept OnSubscribe object
// the most complex creation of Observable
Observable.empty(); //emits nothing and then completes
Observable.never(); //that emits nothing at all
Observable.error(new Throwable("error")); //emits nothing and then signals an error

Empty, Never, Error

Just

Observable.just("Hello", "World", "!").subscribe(new Subscriber<String>() {
            @Override
            public void onCompleted() {
                System.out.println("Completed");
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(String s) {
                System.out.println("Next: " + s);
            }
        });

Output

Next: Hello
Next: World
Next: !
Completed

Interval

Observable.interval(500, TimeUnit.MILLISECONDS)
                .toBlocking()
                .subscribe(new Action1<Long>() {
            @Override
            public void call(Long aLong) {
                System.out.println("Iteration");
            }
        });
create an Observable that emits a sequence of integers spaced by a particular time interval

From

List<String> arr = Arrays.asList("Hello", "World");
// create Observable from:
Observable.from(arr); // from Iterable
Observable.from(new String[]{"Hello", "World"}); // from Array
Observable.fromCallable(() -> "Hello"); // from Callable
convert some other object or data structure into an Observable

Text

Subscribing

with Subscriber 

with Action1 

.subscribe(new Subscriber<Forecast>() {
    @Override
    public void onCompleted() {

    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onNext(Forecast forecast) {

    }
});
.subscribe(new Action1<Forecast>() {
    @Override
    public void call(Forecast forecast) {

    }
});
.subscribe(new Action1<Forecast>() {
    @Override
    public void call(Forecast forecast) {

    }
}, new Action1<Throwable>() {
    @Override
    public void call(Throwable throwable) {
        
    }
});

Real Example with Operators

public static Observable<String> getObservable(String[] arr) {
        return Observable.create((Observable.OnSubscribe<String>) subscriber -> {
            for (String s : arr) {
                subscriber.onNext(s);
            }
            subscriber.onCompleted();
        });
    }
create observable
Hello
GDG
Ternopil
!
output

Transformation

  • map
{Hello}
{GDG}
{Ternopil}
{!}
output
getObservable(new String[]{"Hello", "GDG", "Ternopil", "!"})
                .map(new Func1<String, String>() {
                    @Override
                    public String call(String s) {
                        return "{" + s + "}";
                    }
                })
                .subscribe(System.out::println);

what you get

 emit type

  • flatmap
getObservable(new String[]{"Hello", "GDG", "Ternopil", "!"})
                .flatMap(new Func1<String, Observable<Integer>>() {
                    @Override
                    public Observable<Integer> call(String s) {
                        return Observable.just(s.hashCode());
                    }
                })
                .subscribe(System.out::println);
  • scan
getObservable(new String[]{"Hello", "GDG", "Ternopil", "!"})
                .scan(new Func2<String, String, String>() {
                    @Override
                    public String call(String s, String s2) {

                        return s + " " + s2;
                    }
                }).subscribe(System.out::println);
Hello
HelloGDG
HelloGDGTernopil
HelloGDGTernopil!
output

Filtering

getObservable(new String[]{"Hello", "GDG", "Ternopil", "!"})
                .filter((s) -> !s.startsWith("H"))
                .subscribe(System.out::println);
output
examples
GDG
Ternopil
!
getObservable(new String[]{"Hello", "GDG", "Ternopil", "!"})
                .filter((s) -> !s.startsWith("H"))
                .take(2)
                .subscribe(System.out::println);
GDG
Ternopil
getObservable(new String[]{"Hello", "GDG", "Ternopil", "!"})
                .filter((s) -> !s.startsWith("H"))
                .take(2)
                .last()
                .subscribe(System.out::println);
Ternopil

Combining

public static Observable<String> getObservable2(String name) {
        return Observable.create((Observable.OnSubscribe<String>) subscriber -> {
            subscriber.onNext(name);
            subscriber.onCompleted();
        });
    }
getObservable(new String[]{"Hello", "GDG", "Ternopil", "!"})
                // save executing sequence
                .concatWith(getObservable2("Observable2"))
                // gets the first emitted element
                .mergeWith(getObservable2("Observable2"))
                .subscribe(System.out::println);
Hello
GDG
Ternopil
!
Observable2
output

How to execute it in Background?

Observable.create(subscriber -> {
      for (int i = 0; i < 500; i++) {
        try {
          Thread.sleep(500);
          subscriber.onNext("Hello");
        } catch (InterruptedException e) {
          subscriber.onError(e);
        }
      }
      subscriber.onCompleted();
    })
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

Execute on

Get Result on

.subscribeOn(Schedulers.newThread())
.subscribeOn(Schedulers.computation())
.subscribeOn(Schedulers.from(Executor))

Problems

Observable.create(subscriber -> {
      ...
    })
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())

Memory Leaks

RxLifecycle

Written by

Installation

compile 'com.trello:rxlifecycle:0.4.0'

// If you want pre-written Activities and Fragments you can subclass as providers
compile 'com.trello:rxlifecycle-components:0.4.0'
Usage
1.
2.
MainActivity extends RxAppCompatActivity
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(bindToLifecycle())
or
Create PublishSubject
public class MainActivity extends Activity {
  PublishSubject<ActivityEvent> subject = PublishSubject.create();
}
Override lifecycle methods
@Override
protected void onDestroy() {
  super.onDestroy();
  subject.onNext(ActivityEvent.DESTROY);
}

@Override
protected void onStop() {
  super.onStop();
  subject.onNext(ActivityEvent.STOP);
}
set up in compose()
.compose(RxLifecycle.bindActivity(subject));

Retrofit 2.0 and Realm

RxJava is Everywhere

@GET("/user/{id}/photo")
Observable<Photo> getUserPhoto(@Path("id") int id);
Retrofit Example:
Realm Example:
Realm realm = Realm.getDefaultInstance();
RealmResults<Person> persons = realm.where(Person.class).findAll();
Person person = persons.first();

Observable<Realm> realmObservable = realm.asObservable();
Observable<RealmResults<Person>> resultsObservable = persons.asObservable();
Observable<Person> objectObservable = person.asObservable();

Design app architecture with RxJava

Implement Repository Pattern
Cache Observables
Turn on your imagination

Repository Pattern

Observable Caching

Observable observable = Observable.create(subscriber -> {

    })
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .compose(bindToLifecycle())
        .cache();
You need save instance of observable
  • Loader
  • Singleton
  • Fragment
with:

With Loader

public class ObservableLoader extends Loader<List<Observable>>
private SparseArray<Observable> observableSparseArray;
private Map<String, Observable> observableMap;
or
public void addObservable(Observable<Integer> observable, String id)
@Override
protected void onStartLoading() {
  super.onStartLoading();
  deliverResult(getObservableList());
}
1.
Implement own loader realization

With Loader

2.
In Activity or Fragment
Init Loader and check the presence of observable by id
Get instance of Loader
getLoaderManager().getLoader(1);
Add Observable to map in Loader

Rx World

RxPermission
RxNetty
RxStore
RxLoader
RxPalette
RxBlur

or

Write your own library

Questions & Answers

contact me:
Facebook - silvestr.predko
Twitter - @Silvestr1994
Google+ - SilvestrPredko

Android Application Architecture with RxJava

By Silvestr Predko

Android Application Architecture with RxJava

  • 1,519