Kiedy używać RxJava w Androidzie, a kiedy LiveData z Android Architectural Components?

186

Nie dostaję powodu, by używać RxJava w Androidzie i LiveData z Android Architectural Components. Bardzo pomocne byłoby wyjaśnienie przypadków użycia i różnic między nimi oraz przykładowy przykład w postaci kodu, który wyjaśnia różnice między nimi.

rahul66
źródło
6
Znalazłeś już dobry powód? Zastanawiam się nad tym samym ...
IgorGanapolsky

Odpowiedzi:

117

Android LiveData jest odmianą oryginalnego wzorca obserwatora, z dodatkiem aktywnych / nieaktywnych przejść. Jako taki ma bardzo restrykcyjny zakres.

Korzystając z przykładu opisanego w Android LiveData , tworzona jest klasa do monitorowania danych lokalizacji oraz rejestracji i wyrejestrowania na podstawie stanu aplikacji.

RxJava zapewnia operatory, które są znacznie bardziej uogólnione. Załóżmy, że to możliwe do zaobserwowania dostarczy danych o lokalizacji:

Observable<LocationData> locationObservable;

Implementację obserwowalnego można zbudować za pomocą Observable.create()mapowania operacji oddzwaniania. Po subskrybowaniu obserwowalnego, połączenie zwrotne jest rejestrowane, a gdy nie jest subskrybowane, połączenie zwrotne nie jest rejestrowane. Implementacja wygląda bardzo podobnie do kodu podanego w przykładzie.

Załóżmy również, że masz obserwowalne, które emituje wartość true, gdy aplikacja jest aktywna:

Observable<Boolean> isActive;

Następnie możesz zapewnić wszystkie funkcje LiveData w następujący sposób

Observable<LocationData> liveLocation =
  isActive
    .switchMap( active -> active ? locationObservable : Observable.never() );

switchMap()Operator będzie albo zapewnić bieżącą lokalizację jako strumień lub nic, jeśli aplikacja nie jest aktywna. Gdy już będziesz mieć liveLocationobserwowalne, możesz zrobić z nim wiele rzeczy, używając operatorów RxJava. Mój ulubiony przykład to:

liveLocation.distinctUntilChanged()
  .filter( location -> isLocationInAreaOfInterest( location ) )
  .subscribe( location -> doSomethingWithNewLocation( location ) );

Spowoduje to wykonanie akcji tylko po zmianie lokalizacji, a lokalizacja jest interesująca. Możesz tworzyć podobne operacje, które łączą operatory czasu w celu określenia prędkości. Co ważniejsze, można zapewnić szczegółową kontrolę operacji wykonywanych w wątku głównym, wątku w tle lub wielu wątkach, używając operatorów RxJava.

Chodzi o to, że RxJava łączy kontrolę i synchronizację czasową w jednym wszechświecie, wykorzystując operacje z biblioteki, a nawet operacje niestandardowe, które udostępniasz.

LiveData dotyczy tylko jednej niewielkiej części tego wszechświata, co jest odpowiednikiem budowania liveLocation.

Bob Dalgleish
źródło
2
Dzięki, dokumenty LiveData nie odnoszą się już do próbki lokalizacji. Jest więcej interesujących punktów (z próbką lokalizacji) tutaj: androidkt.com/livedata
Daniel Wilson
5
@DanielWilson link nie jest już dostępny.
Tura,
Koleś, nie pamiętam wtf był pod tym linkiem: DI jak przykładowy kod Marka Allisona dla danych na żywo: blog.stylingandroid.com/architecture-components-livedata
Daniel Wilson
3
The point of RxJava is that it combines control and timing into a single universe, using operations provided from the library, or even custom operations that you provide. Ale cykl życia LiveData nie jest świadomy. Gdybyśmy mieli użyć Rx, czy nie musielibyśmy radzić sobie ze zmianami cyklu życia?
Sparker0i
@ Sparker0i dostałem punkt tutaj. RxJava nie jest świadomy cyklu życia. musimy obsługiwać ręcznie. gdzie, podobnie jak w LiveData, jest już zadbany o cykl życia.
Aks4125,
119

Jeśli chodzi o oryginalne pytanie, zarówno RxJava, jak i LiveData bardzo dobrze się uzupełniają.

LiveDataświeci na warstwie ViewModel, dzięki ścisłej integracji z cyklami życia Androida i ViewModel. RxJavazapewnia więcej możliwości transformacji (jak wspomniano w @Bob Dalgleish).

Obecnie używamy RxJavaw źródłach danych i warstwach repozytoriów, a przekształca się je LiveData(używa LiveDataReactiveStreams) w ViewModels (przed wystawieniem danych na działania / fragmenty) - całkiem zadowolony z tego podejścia.

kzotin
źródło
8
Jeśli dobrze cię zrozumieliśmy, LiveData jest przydatny tylko dla implementacji specyficznych dla interfejsu użytkownika Androida. Jeśli tylko budujemy ogólną aplikację za pomocą Clean Architecture i udostępniamy tę architekturę innym platformom, to RxJava jest lepszym rozwiązaniem niż LiveData?
IgorGanapolsky
@IgorGanapolsky, jakiego języka / frameworku używasz w ogólnej aplikacji?
kzotin
Niezależne od Androida interfejsy API i Clean Arch napisane w Javie / Kotlin.
IgorGanapolsky
1
czy możesz zasugerować w swojej odpowiedzi jakiś działający przykład LiveDataReactiveStreams?
Pawan
2
@ kzotin nie potrzebujesz tego observeOn, LiveDataReactiveStreamsrobi to mimo to dzwoniąc LiveData.postValue(). I nie ma gwarancji subscribeOn, że ogólnie będziesz mieć jakikolwiek efekt.
arekolek
77

Istnieje wiele różnic między LiveData i RxJava:

  1. LiveData nie jest STREAM, podczas gdy w RxJava wszystko (dosłownie wszystko) jest STREAM .
  2. LiveData to obserwowalna klasa posiadaczy danych. W przeciwieństwie do zwykłych obserwowalnych, LiveData ma świadomość cyklu życia, co oznacza, że ​​szanuje cykl życia innych komponentów aplikacji, takich jak działania, fragmenty lub usługi. Ta świadomość zapewnia, że ​​LiveData aktualizuje tylko obserwatory komponentów aplikacji, które są w stanie aktywnego cyklu życia.
  3. LiveData jest synchroniczna , więc nie można wykonać części kodu (połączenie sieciowe, manipulowanie bazą danych itp.) Asynchronicznie, używając tylko LiveData, tak jak w przypadku RxJava.
  4. Aby najlepiej wykorzystać ten duet, najlepiej jest użyć RxJava do logiki biznesowej (połączenie sieciowe, manipulacja danymi itp., Wszystko, co dzieje się w repozytorium i poza nim ) oraz użyć LiveData do warstwy prezentacji. W ten sposób uzyskuje się możliwości transformacji i przesyłania strumieniowego dla logiki biznesowej i operacji uwzględniających cykl życia dla interfejsu użytkownika.
  5. LiveData i RxJava uzupełniają się, jeśli są używane razem. Chodzi mi o to, że rób wszystko za pomocą RxJava, a na koniec, gdy chcesz zaktualizować interfejs, zrób coś takiego, jak kod podany poniżej, aby zmienić Observable na LiveData. Tak więc Twój widok (UI) obserwuje LiveData w ViewModel, gdzie twoje LiveData jest niczym innym jak niemodyfikowalną MutableLiveData (lub MutableLiveData jest mutable LiveData).
  6. Pytanie brzmi: dlaczego w ogóle należy korzystać z LiveData? Jak widać poniżej w kodzie, przechowujesz swoją odpowiedź z RxJava na MutableLiveData (lub LiveData), a Twoje LiveData ma świadomość cyklu życia, więc w pewnym sensie twoje dane są świadome cyklu życia. Teraz wyobraź sobie możliwość, kiedy twoje dane wiedzą, kiedy i kiedy nie, aby zaktualizować interfejs użytkownika.
  7. LiveData nie ma historii (tylko bieżący stan). Dlatego nie należy używać LiveData do czatu.
  8. Kiedy używasz LiveData z RxJava, nie potrzebujesz takich rzeczy jak MediatorLiveData , SwitchMap itp. Są to narzędzia do kontroli strumienia, a RxJava jest w tym lepszy.
  9. Zobacz LiveData jako posiadacz danych i nic więcej. Możemy również powiedzieć, że LiveData jest konsumentem świadomym cyklu życia.

    public class RegistrationViewModel extends ViewModel {
        Disposable disposable;

        private RegistrationRepo registrationRepo;
        private MutableLiveData<RegistrationResponse> modelMutableLiveData =
                new MutableLiveData<>();

        public RegistrationViewModel() {
        }

        public RegistrationViewModel(RegistrationRepo registrationRepo) {
            this.registrationRepo = registrationRepo;
        }

        public void init(RegistrationModel registrationModel) {
            disposable = registrationRepo.loginForUser(registrationModel)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Consumer<Response<RegistrationResponse>>() {
                        @Override
                        public void accept(Response<RegistrationResponse>
                                                   registrationModelResponse) throws Exception {

                            modelMutableLiveData.setValue(registrationModelResponse.body());
                        }
                    });
        }

        public LiveData<RegistrationResponse> getModelLiveData() {
            return modelMutableLiveData;
        }

       @Override
       protected void onCleared() {
                super.onCleared();
            disposable.dispose();
         }
    }
Abhishek Kumar
źródło
5
Zobacz LiveData jako posiadacz danych i nic więcej. ==> TAK
Lou Morda
3
Niezły przykład. Zapomniałeś zadeklarować jednorazowe i dobrze byłoby je wyczyścić onCleared.
Snicolas
Czy mógłbyś wyjaśnić, jak żywa jest synchroniczna? O ile mi wiadomo, możemy wysłać obiekt Livedata do innego wątku, a następnie ten wątek może przesunąć wartość, którego obserwator może słuchać w MainThread.
Hitesh Bisht
Jeśli ponownie przeczytasz, co napisałem, oznacza to, że nie możesz pracować nad innym wątkiem tylko (TAK, użyłem „tylko” nawet tam) za pomocą LiveData, tak jak możesz to zrobić przy użyciu RxJava
Abhishek Kumar
Czy cykl życia nie jest dużym wyróżnikiem LiveData? 1. opisujesz, co musi zrobić Twój rurociąg i jakie są Twoje końcowe wyniki, 2. subskrybujesz wynik w klauzulach „przestrzegaj”, A następnie 3. rurociąg jest eksploatowany tylko wtedy, gdy pozwala na to Twój cykl życia.
Srg
29

W rzeczywistości, LiveData nie jest zasadniczo różne narzędziem RxJava, więc dlaczego został wprowadzony jako składnik architektury kiedy RxJavamógł łatwo zarządzać cyklem przechowując wszystkie subskrypcje obserwabli w CompositeDispoable obiekcie, a następnie usuwania ich onDestroy() z Activity lub onDestroyView() z Fragment użyciem tylko jednego wiersz kodu?

Odpowiedziałem na to pytanie w pełni, budując aplikację do wyszukiwania filmów raz, używając RxJava, a następnie używając LiveData tutaj .

Krótko mówiąc, tak, może, ale wymagałoby to najpierw zastąpienia odpowiednich metod cyklu życia, oprócz posiadania podstawowej wiedzy o cyklu życia. Dla niektórych może to nadal nie mieć sensu, ale faktem jest, że według jednej z sesji Jetpack w Google I / O 2018 wielu programistów uważa kompleks zarządzania cyklem życia. Błędy awaryjne wynikające z braku obsługi zależności cyklu życia mogą być kolejnym znakiem, że niektórzy programiści, nawet jeśli znają się na cyklu życia, zapominają o tym zadbać w każdym działaniu / fragmencie używanym w swojej aplikacji. W dużych aplikacjach może to stanowić problem, pomimo negatywnego wpływu na produktywność.

Najważniejsze jest to, że po wprowadzeniu oczekuje się, że LiveDatawiększa liczba programistów przyjmie MVVM bez konieczności rozumienia zarządzania cyklem życia, wycieku pamięci i awarii. Mimo że nie mam wątpliwości, że LiveDatanie jest to porównywalne RxJavapod względem możliwości i mocy, jaką daje programistom, reaktywnego programowania i RxJavajest trudnym do zrozumienia pojęciem i narzędziem dla wielu. Z drugiej strony, nie sądzę, że LiveDatama być zamiennikiem RxJava- po prostu nie może - ale bardzo prostym narzędziem do obsługi kontrowersyjnego, szeroko rozpowszechnionego problemu, którego doświadcza wielu programistów.

** AKTUALIZACJA ** Dodałem tutaj nowy artykuł , w którym wyjaśniłem, w jaki sposób niewłaściwe użycie LiveData może prowadzić do nieoczekiwanych rezultatów. RxJava może przyjść na ratunek w takich sytuacjach


Ali Nem
źródło
2
„dlaczego został wprowadzony, gdy RxJava mógł łatwo zarządzać cyklem życia, przechowując wszystkie subskrypcje w CompositeDispoable, a następnie umieszczając je w onDestroy () działania” - LiveDatamiałby się onStopfaktycznie pozbyć
arekolek
@arekolek z mojego zrozumienia: nawet do obsługi CompositeDispoable mamy nadpisać metody cyklu życia. Ale w danych na żywo wszystkie będą zawarte w jednym wierszu kodu. Zapisujemy więc minimum 20 linii kodu.
Suresh
Możemy zdefiniować baseFragment i zdefiniować metodę subskrypcji Disposable [], która ma zostać przesłonięta przez wszystkie pochodne fragmenty, wywołać tę metodę w onCreateView i dodać wartość zwracaną w CompositeDisposable, usunąć to w onDestroyView, nie zapominając o tym.
android2013
Nie chodzi tylko o utylizację. Korzystając z RxJava, musisz się pozbyć na onStop, a następnie ponownie zasubskrybować w onStart / onResume, obsłużyć zmiany konfiguracji i zrobić wiele innych rzeczy. Właśnie dlatego tak wiele awarii powoduje użycie RxJava. LiveData obsługuje to wszystko, ale nie jest tak elastyczny jak RxJava.
user932178,
24

Jak zapewne wiesz w reaktywnym ekosystemie, mamy obserwowalny, który emituje dane i obserwatora, który subskrybuje (otrzyma powiadomienie) o tej obserwowalnej emisji, nic dziwnego, jak działa tak zwany wzorzec obserwatora. Obserwowalne coś „krzyczy”, Obserwator zostaje powiadomiony, że Obserwowalny coś krzyczy w danym momencie.

Myśl LiveDatajako obserwowalny, który pozwala zarządzać obserwatorami będącymi w activestanie. Innymi słowy LiveDatajest prosty do zaobserwowania, ale także dba o cykl życia.

Ale zobaczmy dwa przypadki kodu, o które prosisz:

A) Dane na żywo

B) RXJava

A) Jest to podstawowa implementacja LiveData

1) zazwyczaj tworzysz LiveData w ViewModel, aby zachować zmianę orientacji (możesz mieć LiveData tylko do odczytu lub MutableLiveData, który jest zapisywalny, więc zwykle eksponujesz poza klasą LiveData)

2) w OnCreatemetodzie Main Activity (nie ViewModel) „subskrybujesz” obiekt Observer (zwykle metoda onChanged)

3) uruchomisz metodę obserwuj, aby ustanowić link

Po pierwsze ViewModel(posiada logikę biznesową)

class ViewModel : ViewModel() { //Point 1

    var liveData: MutableLiveData<Int> = MutableLiveData()

}

I to jest MainActivity(tak głupie, jak to możliwe)

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val ViewModelProvider= ViewModelProviders.of(this).get(ViewModel::class.java)

        ViewModelProvider.observe(this, Observer {//Points 2 and 3
            //what you want to observe
        })


        }
    }
}

B) To jest podstawowa implementacja RXJava

1) oświadczasz, że jest obserwowalny

2) deklarujesz obserwatora

3) subskrybujesz Obserwowalny wraz z Obserwatorem

Observable.just(1, 2, 3, 4, 5, 6) // Point 1

   .subscribe(new Subscriber() {    //Points 2 & 3
       @Override
       public void onCompleted() {
           System.out.println("Complete!");
       }

       @Override
       public void onError(Throwable e) {
       }

       @Override
       public void onNext(Double value) {
           System.out.println("onNext: " + value);
       }
    });

W szczególności LiveDatajest stosowany z komponentami architektury Lifecyclei ViewModel(jak widzieliśmy) często . W rzeczywistości w LiveDatapołączeniu z ViewModel pozwala na bieżąco aktualizować każdą zmianę w Observerie, dzięki czemu wydarzenia są zarządzane w czasie rzeczywistym tam, gdzie jest to potrzebne. Aby korzystać LiveDatazaleca się poznać koncepcję cyklu życia i względne obiekty LifeCycleOwner / Lifecycle , również chciałbym zaproponować Ci spojrzeć na przekształceniach , jeśli chcesz wprowadzić LiveDataw realnych sytuacjach życiowych. Tutaj możesz znaleźć kilka przykładów użycia z wielkiego wspólnego oprogramowania .

Omotać zasadzieLiveDatajest uproszczonaRXJava, elegancki sposób, aby obserwować zmiany w wielu komponentów bez tworzenia jawnych tzw zasady zależnościami pomiędzy komponentami, dzięki czemu można przetestować wiele łatwiej kod i sprawiają, że o wiele bardziej czytelny. RXJava, pozwala robić rzeczy LiveData i wiele więcej. Ze względu na rozszerzone funkcjonalności RXJava, możesz zarówno używać LiveData do prostych przypadków, jak i wykorzystywać całą moc RXJava, używając komponentów architektury Android jako ViewModel , oczywiście oznacza to, żeRXJavamoże być o wiele bardziej skomplikowane, po prostu pomyśl o setkach operatorów SwitchMap i Map LiveData (w tej chwili).

RXJava wersja 2 to biblioteka, która zrewolucjonizowała paradygmat obiektowy, dodając tak zwany funkcjonalny sposób zarządzania przepływem programu.

trocchietto
źródło
4

LiveData to podzbiór komponentów architektury Androida opracowany przez zespół Androida.

W przypadku danych na żywo i innych komponentów architektury, wycieki pamięci i inne podobne problemy są obsługiwane przez komponenty architektury. Ponieważ został opracowany przez zespół Androida, jest najlepszy dla Androida. Zapewniają także aktualizacje obsługujące nowe wersje Androida.

Jeśli chcesz używać tylko do tworzenia aplikacji na Androida, wybierz komponenty architektury Androida. W przeciwnym razie, jeśli chcesz użyć innej aplikacji Java, takiej jak aplikacja internetowa, aplikacje komputerowe itp., Użyj RxJava

SIVAKUMAR.J
źródło
Próbowałem wyjaśnić twoją odpowiedź. Jeśli w jakikolwiek sposób koliduję z twoimi pierwotnymi intencjami, możesz edytować. Jeśli to zrobisz, spróbuj uczynić go bardziej zrozumiałym niż początkowa wersja. Ostatnia część twojej odpowiedzi szczerze mówiąc nie miała sensu.
Zoe
2

LiveDatajako rzecz posiadacza danych i nic więcej. Możemy również powiedzieć, że LiveData jest konsumentem świadomym cyklu życia. LiveDatazaleca się znajomość koncepcji cyklu życia i względnych obiektów LifeCycleOwner / LifeCycle, aby uzyskać możliwości transformacji i przesyłania strumieniowego dla logiki biznesowej i operacji uwzględniających cykl życia dla interfejsu użytkownika.

Rx to potężne narzędzie, które umożliwia rozwiązanie problemu w eleganckim stylu deklaratywnym. Obsługuje opcje biznesowe lub operacje interfejsu API usługi

Attif
źródło
0

Porównując LiveData do RxJava porównuje jabłka z sałatkami owocowymi.

Porównaj LiveData do ContentObserver i porównujesz jabłka z jabłkami. LiveData skutecznie zastępuje ContentObserver z uwzględnieniem cyklu życia.

Porównywanie RxJava do AsyncTask lub dowolnego innego narzędzia do gwintowania to porównywanie sałatek owocowych z pomarańczami, ponieważ RxJava pomaga w czymś więcej niż tylko wątkowaniu.

straya
źródło
0
  • LiveData częściowo odpowiada Rx Subject lub SharedRxObservable

  • LiveData zarządza cyklem życia subskrypcji, ale subskrypcja Rx Subject powinna być tworzona i usuwana ręcznie

  • LiveData nie ma stanu zakończenia, ale Rx Subject ma OnError i OnCompleted

Sergey M.
źródło