Slide 1

Slide 1 text

RXJAVA REFACTORING FOR UBIRATAN SOARES SEPTEMBER / 2016

Slide 2

Slide 2 text

MOTIVAÇÕES RxJava é um dos trending topics no desenvolvimento para Android nos últimos 2+ anos Você certamente já viu alguma solução “Rxfyed" para algum problema na sua timeline. Fato : programação reativa oferece soluções poderosas para problemas difíceis Fato : RxJava irá alcançar o release 2.0.0 em breve, uma atualização significativa com novas funcionalidades e várias mudanças

Slide 3

Slide 3 text

ESSA PARECE SER UMA ÓTIMA PERGUNTA ! Seu me projeto não utiliza nada de RxJava hoje, como eu o refatoro para ter acesso à essas benesses divinas?

Slide 4

Slide 4 text

restAPI.endpoint() .compose(Transformers::handleNetworkingError) .onErrorResumeNext(t-> handleError(t)) .map(payload -> payload.array) .flatMap(Observable::from) .filter(DataValidation::validate) .map(ModelTransformer::toUI) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(
 data -> updateUI(data),
 this::reportError,
 () -> Timber.d(“DONE”)
 ); SUA REAÇÃO ?

Slide 5

Slide 5 text

ANTES DE TUDO ENTENDER RXJAVA

Slide 6

Slide 6 text

DATA TRANSFORMER VISÃO SIMPLIFICADA OBSERVABLE OBSERVER FUNCTIONAL OPERATION DATA SOURCE FUNCTIONAL OPERATION DATA CONSUMER …

Slide 7

Slide 7 text

UM GUIA ENVIESADO 1 2 3 4 Identifique uma fonte de emissões reativas e defina o tipo de fluxo desses dados Adaptar e evoluir as camadas da sua aplicação para orquestrar o fluxo de dados, ligando fonte a consumidor Identifique em que ponto da sua aplicação você quer receber esses dados (Observer / Subscriber) Se as fontes de dados mais óbvias já esgotaram, hora de avançar para as não-óbvias. Retornar para passo 01

Slide 8

Slide 8 text

REACTIVE DATA SOURCES “Like bugs, you can find them everywhere in your code” - Soares, U.

Slide 9

Slide 9 text

ANTES (ASYNCTASK) private void notSoTastyThreading(String input) { new AsyncTask() { @Override protected void onPreExecute() { notifyProcessingBeforeInit(); } @Override protected String doInBackground(String... params) { return processing(params[0]); } @Override protected void onPostExecute(String result) { handleResult(result); } }.execute(input); }

Slide 10

Slide 10 text

DEPOIS (THREADING COM RXJAVA) private void beatifulThreading(String input) {
 Observable.just(input)
 .doOnSubscribe(this::notifyProcessingBeforeInit)
 .map(this::processing)
 .subscribeOn(Schedulers.computation())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::handleResult); }

Slide 11

Slide 11 text

ANTES (TIMERTASK) Handler toMainThread = new Handler(Looper.getMainLooper());
 
 TimerTask periodic = new TimerTask() {
 @Override public void run() {
 toMainThread.post(() -> updateUI());
 }
 };
 
 Timer timer = new Timer();
 timer.schedule(periodic, NO_DELAY, PERIOD_IN_MILIS);
 . . . timer.purge();

Slide 12

Slide 12 text

DEPOIS (TIMER COM RXJAVA) Subscription timer = Observable.timer(PERIOD_IN_SECONDS, TimeUnit.SECONDS)
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(instant -> updateUI());
 . . . timer.unsubscribe()

Slide 13

Slide 13 text

ANTES (RETROFIT VIA CALL PATTERN) api.movieWithId(movieId);
 .enqueue(new Callback() {
 @Override public void onResponse( Call call, Response response) {
 if(response.isSuccessful()) {
 // Success
 } else {
 // 4xx or 5xx
 }
 }
 @Override public void onFailure(Call call, Throwable t) { // Deu ruim mesmo
 }
 });

Slide 14

Slide 14 text

DEPOIS (RETROFIT COM RXJAVA) starWarsAPI.people() .subscribeOn(Schedulers.io()) .flatMap(payload -> Observable.from(payload.results)) .observeOn(AndroidSchedulers.mainThread()) .subscribe(
 data -> addToList(data),
 Throwable::printStackTrace,
 () -> adapter.notifyDataSetChanged()
 );

Slide 15

Slide 15 text

E PARA ENCADEAR DUAS OPERAÇÕES ASSÍNCRONAS ?

Slide 16

Slide 16 text

ANTES : CHAINING CALLBACKS

Slide 17

Slide 17 text

DEPOIS : CHAINING COM RXJAVA starWarsApi.people() .subscribeOn(Schedulers.io()) .flatMap(payload -> selectRandomPeople(payload.results)) .doOnNext(System.out::println) .flatMap(people -> Observable.from(people.films)) .flatMap(filmUrl -> { String filmId = ResourceIdExtractor.idFromUrl(filmUrl); return api.movieById(filmId)
 }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(
 data -> addToMoviesList(data),
 Throwable::printStackTrace,
 () -> moviesAdapter.notifyDataSetChanged()
 );

Slide 18

Slide 18 text

FLATTENING (MERGE) MAPPING (PROVIDED FUNCTION) FLATMAP

Slide 19

Slide 19 text

REACTIVE SOURCES NA INTERFACE RxBinding to the rescue! É possível adaptar outros callbacks utilizando Subjects ou o utilitário fromAsync / fromEmitter Atenção ao lidar com operadores que envolvam tempo : eles já trocam o Scheduler da sequência, é preciso ressincronizar com a UI Thread para atualizações na UI

Slide 20

Slide 20 text

SEARCHVIEW (RX WAY) @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_search_by_terms, menu);
 MenuItem search = menu.findItem(R.id.search);
 SearchView searchView = (SearchView) MenuItemCompat.getActionView(search);
 
 RxSearchView.queryTextChangeEvents(searchView)
 .debounce(300, TimeUnit.MILLISECONDS)
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::proceedWithQuery);
 
 return true;
 }

Slide 21

Slide 21 text

DEFINING YOUR OBSERVERS “Ideas are bullet proof” - V

Slide 22

Slide 22 text

OBSERVER (NORMAL WAY) api.getAvaliableItems(), .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer>() { @Override public void onCompleted() { … } @Override public void onError(Throwable e) { … } @Override public void onNext(List items) { … } } );

Slide 23

Slide 23 text

OBSERVER (ACTIONS WAY) Observable.fromCallable(() -> “Better subscribing with actions”) .subscribe( System.out::println, throwable -> someErrorAction(), () -> done() );

Slide 24

Slide 24 text

IMPORTANTE SEMPRE IMPLEMENTE onError( ) em seus Observers/ Subscribers, com Actions ou não Observers / Subscribers causam memory leaks se retidos em Activities / Fragments / etc Controle no ciclo de vida via Subscription Evite Subscribers (statefull)

Slide 25

Slide 25 text

Subscription first = Observable.interval(1, TimeUnit.SECONDS)
 .subscribe(System.out::print);
 
 Subscription second = Observable.range(1, 100000)
 .subscribe(System.out::print);
 
 CompositeSubscription subs = new CompositeSubscription();
 subs.add(first);
 subs.add(second); // . . . 
 first.unsubscribe(); subs.add(third); 
 if(subs.hasSubscriptions()) subs.unsubscribe();

Slide 26

Slide 26 text

EVOLVING YOUR ARCHITECTURE “Tradeoffs? Wellcome to Engineering” - Uncle Bob Martin

Slide 27

Slide 27 text

UMA APLICAÇÃO DOS DIAS ANTIGOS REST API MANAGER ACTIVITY FRAGMENT Callback EventBus

Slide 28

Slide 28 text

UMA APLICAÇÃO DOS DIAS MODERNOS PRESENTER ACTIVITY FRAGMENT VIEW MODELS / EXTERNAL WORLD ADAPTERS

Slide 29

Slide 29 text

PRESENTER VIEW (IMPL) MODEL MANAGER ACTIVITY / FRAGMENT As direções de fluxo de dados indicam como você pode substituir callbacks / eventos por uma sequência observável!

Slide 30

Slide 30 text

PRESENTER VIEW (IMPL) MODEL MANAGER ACTIVITY / FRAGMENT Caso 01 : as emissões serão geradas nas camadas mais internas da aplicação e consumidas nas camadas mais próximas à UI (Presenter ou Android)

Slide 31

Slide 31 text

PRESENTER VIEW (IMPL) MODEL MANAGER ACTIVITY / FRAGMENT Caso 02 : as emissões são originadas da UI e consumidas nas camadas internas mais da aplicação

Slide 32

Slide 32 text

REACTIVE MVP PRESENTER ACTIVITY / FRAGMENT / VIEW RX SOURCE Observable Observable Observable Observable

Slide 33

Slide 33 text

REACTIVE CLEAN ARCHITECTURE PRESENTER RX SOURCE Observable Observable Observable REST API PREFS DB ACTIVITY FRAGMENT ETC PLATFORM USECASE Observable

Slide 34

Slide 34 text

CONSIDERAÇÕES PRÁTICAS Consumir emissões no Presenter vs View Passiva ? Consumir emissões no Android vs View Reativa ? Consumo de emissões na UI vs Repository passivo(s) ? Emissão na UI e consumo no Repository reativo? Como lidar com estado no Presenter? Como driblar boilerplating da replicação de dados? Como testar tudo isso?

Slide 35

Slide 35 text

NON-OBVIOUS REACTIVE SOURCES “Let`s catch them all” Ash

Slide 36

Slide 36 text

ONDE PROCURAR? Qualquer callback de uso recorrente pode ser encapsulado para emitir eventos em uma sequência observável Android Framework está cheio deles! APIs de suporte estão cheias deles! PlayServices e adendos estão cheios deles! ETC

Slide 37

Slide 37 text

class GoogleApiClientObservable extends BaseClient implements Action1> { private final Api api; private AsyncEmitter emitter; private GoogleApiClientObservable(Context context, Api api) { super(context); this.api = api; } static Observable create(Context context, Api api) { return Observable.fromAsync(new GoogleApiClientObservable(context, api), BackpressureMode.NONE); } @Override public void call(AsyncEmitter emitter) { this.emitter = emitter; buildClient(api); connect(); emitter.setSubscription(Subscriptions.create(this::disconnect)); } @Override void onClientConnected(GoogleApiClient googleApiClient) { emitter.onNext(googleApiClient); } @Override void onClientError(Throwable throwable) { emitter.onError(throwable); } } Snippet from Servant https://github.com/Mauin/servant

Slide 38

Slide 38 text

QUANDO NÃO USAR RXJAVA ? “U HAVE NOTHING, NOTHING !!!!” - Al Capone, The Untouchables

Slide 39

Slide 39 text

ALGUM CASOS A CONSIDERAR Valores que não mudam nunca : justificam ser passados por Callback observável? Observer/Subscriber desencadeia uma operação pesada no emissor, e a sequência por sua vez é multicasted Você precisa de snapshots de estados intermediários referentes às emissões por algum motivo Seu design de classes sugere que um Observable até podia ser uma variável membro … ETC

Slide 40

Slide 40 text

FINAL REMARKS "You know nothing, Jon Snow" - Game of Thrones

Slide 41

Slide 41 text

DONT FORGET KIDS Comece pelos casos simples Evolua para os casos complexos Defina quais camadas da sua aplicação são reativas ou não Substitua callbacks/eventos por sequência observáveis FTW

Slide 42

Slide 42 text

REFERÊNCIAS (I) "Functional Reactive Programming with RxJava" by Ben Christensen https://youtu.be/_t06LRX0DV0 “Learning RxJava (for Android) by example“ by Kaushik Goupal https://youtu.be/k3D0cWyNno4 “Demystifying RxJava Subscribers" by Jake Wharton https://youtu.be/NVKmyK6sd-Q “What does it mean to be Reactive ?” by Erik Meijer https://youtu.be/sTSQlYX5DU0

Slide 43

Slide 43 text

REFERÊNCIAS (II) "Grokking RxJava Series” by Dan Lew http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/ “The Introduction to Reactive Programming you`ve been missing” by André Staltz https://gist.github.com/staltz/868e7e9bc2a7b8c1f754 Oficial RxJava Wiki by NetFlix https://github.com/ReactiveX/RxJava/wiki Advanced RxJava Blog by David Karnok akarnokd.blogspot.com

Slide 44

Slide 44 text

REFERÊNCIAS (III) GradleLambda : https://github.com/evant/gradle-retrolambda RxAndroid : https://github.com/ReactiveX/RxAndroid RxLifecycle : https://github.com/trello/RxLifecycle RxBinding : https://github.com/JakeWharton/RxBinding Frodo : https://github.com/android10/frodo

Slide 45

Slide 45 text

speakerdeck.com/ubiratansoares/refactoring-to-rxjava

Slide 46

Slide 46 text

UBIRATAN SOARES Computer Scientist by ICMC/USP Software Engineer @ Luiza Labs Google Developer Expert for Android Teacher, speaker, etc, etc

Slide 47

Slide 47 text

THANKS! THAT`S ALL FOLKS !!! @ubiratanfsoares br.linkedin.com/in/ubiratanfsoares ubiratansoares.github.io