Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rx UI

Rx UI

Cristian Fabian Gómez Rojas

December 06, 2017
Tweet

Transcript

  1. Hola! Soy Cristian Gomez Android developer @PagerInc, Co-Organizer @MedellinAndroid. You

    can find me at: @iyubinest on github, twitter, instagram.
  2. RxJava 2 Single Emite un solo elemento con un valor

    o un error. Completable Emite un evento para saber si el stream ha sido completado. Maybe Emite 0 o 1 elementos o puede fallar. Observable No hay manejo de backpressure. Flowable Permite manejo de backpressure.
  3. Backpressure Default Maneja un buffer, si este buffer se llena

    se produce una excepción. Latest Mientras el elemento actual es procesado , elimina los primeros valores del stream, conservando los últimos. Oldest Mientras el elemento actual es procesado , elimina los últimos valores del stream, conservando los primeros.
  4. Cuando usar Observable ▪ Stream menor a 1000 elementos ▪

    GUI events ▪ Tiene un overhead menor
  5. Cuando usar Flowable ▪ Stream mayor a 10k elementos ▪

    Operaciones de IO ▪ Parsing de datos
  6. Problemas de una UI normal ▪ Manejo del hilo de

    la UI ▫ runOnUiThread ▫ Inyectar mainThread() ▪ Backpressure ▪ Manejo de multiples estados para diferentes elementos graficos
  7. interface FlightView { Observable<String> fromChanges(); Observable<String> toChanges(); Observable<FlightModel> saveClicked(); Consumer<List<String>>

    showFrom(); Consumer<List<String>> showTo(); Consumer<Throwable> showError(); Consumer<Object> showLoading(); Consumer<FlightModel> showSaved(); Consumer<Boolean> showButton(); }
  8. interface FlightView { Observable<String> fromChanges(); Observable<String> toChanges(); Observable<FlightModel> saveClicked(); Consumer<List<String>>

    showFrom(); Consumer<List<String>> showTo(); Consumer<Throwable> showError(); Consumer<Object> showLoading(); Consumer<FlightModel> showSaved(); Consumer<Boolean> showButton(); }
  9. interface FlightView { Observable<String> fromChanges(); Observable<String> toChanges(); Observable<FlightModel> saveClicked(); Consumer<List<String>>

    showFrom(); Consumer<List<String>> showTo(); Consumer<Throwable> showError(); Consumer<Object> showLoading(); Consumer<FlightModel> showSaved(); Consumer<Boolean> showButton(); }
  10. interface FlightView { Observable<String> fromChanges(); Observable<String> toChanges(); Observable<FlightModel> saveClicked(); Consumer<List<String>>

    showFrom(); Consumer<List<String>> showTo(); Consumer<Throwable> showError(); Consumer<Object> showLoading(); Consumer<FlightModel> showSaved(); Consumer<Boolean> showButton(); }
  11. interface FlightView { Observable<String> fromChanges(); Observable<String> toChanges(); Observable<FlightModel> saveClicked(); Consumer<List<String>>

    showFrom(); Consumer<List<String>> showTo(); Consumer<Throwable> showError(); Consumer<Object> showLoading(); Consumer<FlightModel> showSaved(); Consumer<Boolean> showButton(); }
  12. interface FlightView { Observable<String> fromChanges(); Observable<String> toChanges(); Observable<FlightModel> saveClicked(); Consumer<List<String>>

    showFrom(); Consumer<List<String>> showTo(); Consumer<Throwable> showError(); Consumer<Object> showLoading(); Consumer<FlightModel> showSaved(); Consumer<Boolean> showButton(); }
  13. interface FlightView { Observable<String> fromChanges(); Observable<String> toChanges(); Observable<FlightModel> saveClicked(); Consumer<List<String>>

    showFrom(); Consumer<List<String>> showTo(); Consumer<Throwable> showError(); Consumer<Object> showLoading(); Consumer<FlightModel> showSaved(); Consumer<Boolean> showButton(); }
  14. interface FlightView { Observable<String> fromChanges(); Observable<String> toChanges(); Observable<FlightModel> saveClicked(); Consumer<List<String>>

    showFrom(); Consumer<List<String>> showTo(); Consumer<Throwable> showError(); Consumer<Object> showLoading(); Consumer<FlightModel> showSaved(); Consumer<Boolean> showButton(); }
  15. interface FlightView { Observable<String> fromChanges(); Observable<String> toChanges(); Observable<FlightModel> saveClicked(); Consumer<List<String>>

    showFrom(); Consumer<List<String>> showTo(); Consumer<Throwable> showError(); Consumer<Object> showLoading(); Consumer<FlightModel> showSaved(); Consumer<Boolean> showButton(); }
  16. interface FlightView { Observable<String> fromChanges(); Observable<String> toChanges(); Observable<FlightModel> saveClicked(); Consumer<List<String>>

    showFrom(); Consumer<List<String>> showTo(); Consumer<Throwable> showError(); Consumer<Object> showLoading(); Consumer<FlightModel> showSaved(); Consumer<Boolean> showButton(); }
  17. public class FlightWorker extends Fragment { private final FindCity findCity;

    private final SaveFlight saveFlight; private CompositeDisposable disposables = new CompositeDisposable(); public FlightWorker() { setRetainInstance(true); findCity = FindCity.create(); saveFlight = SaveFlight.create(); } void bind(final FlightView view) { disposables.add(autocompleteFrom(view.fromChanges(), view.showFrom())); disposables.add(autocompleteFrom(view.toChanges(), view.showTo())); disposables.add(validateForm(view)); disposables.add(saveFlight(view)); } }
  18. private Disposable autocompleteFrom(Observable<String> textChanges, Consumer<List<String>> publishTo) { return textChanges.switchMap(text ->

    findCity.exec(text).toObservable()) .compose(mainThread()) .subscribe(publishTo, Functions.emptyConsumer()); }
  19. private Disposable validateForm(RealFlightView view) { return Observable.combineLatest(view.fromChanges(), view.toChanges(), (from, to)

    -> !TextUtils.isEmpty(from) && !TextUtils.isEmpty(to)) .compose(mainThread()) .subscribe(view.showButton(), Functions.emptyConsumer()); }
  20. private Disposable saveFlight(RealFlightView view) { return view.saveClicked() .doOnNext(view.showLoading()) .flatMap(saveFlight::save) .map(this::map)

    .doOnError(view.showError()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(view.showSaved(), Functions.emptyConsumer()); }
  21. public final class FindCity { private final AutoCompleteCityApi api; public

    static FindCity create() { return new FindCity(); } private FindCity() { api = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .baseUrl("http://autocompletecity.geobytes.com/") .build() .create(AutoCompleteCityApi.class); } public Maybe<List<String>> exec(String query) { return api.options(query).map(response -> response).observeOn(Schedulers.io()); } interface AutoCompleteCityApi { @GET("AutoCompleteCity") Maybe<List<String>> options(@Query("q") String query); } }
  22. public final class SaveFlight { public class Response {...} private

    final DatabaseReference firebase; public static SaveFlight create() {return new SaveFlight();} private SaveFlight() { firebase = FirebaseDatabase.getInstance().getReference(); } public Observable<Response> save(FlightModel model) { PublishSubject<Response> subject = PublishSubject.create(); firebase.child("/").push().setValue(model, (error, reference) -> { if (null != error) { subject.onError(error.toException()); } else { subject.onNext(new Response(model)); subject.onComplete(); } }); return subject; } }
  23. public Observable<Response> save(FlightModel model) { PublishSubject<Response> subject = PublishSubject.create(); firebase.child("/").push().setValue(model,

    (error, reference) -> { if (null != error) { subject.onError(error.toException()); } else { subject.onNext(new Response(model)); subject.onComplete(); } }); return subject; }
  24. public class FlightActivity extends AppCompatActivity { private FlightWorker worker; @Override

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.flight_activity); worker = new FlightWorker(); worker.bind(new RealFlightView(findViewById(android.R.id.content))); } @Override protected void onDestroy() { super.onDestroy(); worker.unbind(); } }
  25. class RealFlightView implements FlightView { private static final int MIN_LENGTH

    = 3; private static final int DELAY = 500; private final View parent; private final View loadingView; private final FlightToolbar toolbar; private final AutocompleteField fromView; private final AutocompleteField toView; private final FlightListWidget flightsView; private final Button flightsSave; RealFlightView(View view) { parent = view; loadingView = view.findViewById(R.id.flight_loading); toolbar = view.findViewById(R.id.flight_toolbar); fromView = view.findViewById(R.id.flight_from); toView = view.findViewById(R.id.flight_to); flightsView = view.findViewById(R.id.flight_list); flightsSave = view.findViewById(R.id.flight_save); } }
  26. class RealFlightView implements FlightView { ... @Override public Observable<String> fromChanges()

    { return RxTextView.textChanges(fromView).compose(autocomplete()); } @Override public Observable<String> toChanges() { return RxTextView.textChanges(toView).compose(autocomplete()); } @Override public Observable<FlightModel> saveClicked() { return RxView.clicks(flightsSave) .map(object -> new FlightModel(fromView.content(), toView.content())); } @Override public Consumer<List<String>> showFrom() {return this::showFrom;} @Override public Consumer<List<String>> showTo() {return this::showTo;} @Override public Consumer<Throwable> showError() {return this::showError;} @Override public Consumer<Object> showLoading() {return this::showLoading;} @Override public Consumer<FlightModel> showSaved() {return this::addFlight;} @Override public Consumer<Boolean> showButton() {return this::showButton;} ... }
  27. class RealFlightView implements FlightView { ... private void showError(Throwable throwable)

    { loadingView.setVisibility(View.GONE); Toast.makeText(parent.getContext(), throwable.getMessage(), Toast.LENGTH_SHORT).show(); } private void showLoading(Object object) { loadingView.setVisibility(View.VISIBLE); } private void addFlight(FlightModel flightModel) { loadingView.setVisibility(View.GONE); flightsView.add(flightModel); } private void showFrom(List<String> cities) { ArrayAdapter<String> adapter = new ArrayAdapter<>(fromView.getContext(), android.R.layout.simple_list_item_1, cities); fromView.setAdapter(adapter); } }
  28. class RealFlightView implements FlightView { ... private void showTo(List<String> cities)

    { ArrayAdapter<String> adapter = new ArrayAdapter<>(toView.getContext(), android.R.layout.simple_list_item_1, cities); toView.setAdapter(adapter); } private void showButton(Boolean valid) { flightsSave.setEnabled(valid); } private ObservableTransformer<CharSequence, String> autocomplete() { return observable -> observable.debounce(DELAY, TimeUnit.MILLISECONDS) .map(CharSequence::toString) .filter(s -> s.length() > MIN_LENGTH) .distinctUntilChanged() .share(); } }