何时在Android中使用RxJava,何时使用来自Android架构组件的LiveData?

229
我不明白在Android中为什么要使用RxJava和LiveData(来自Android Architectural Components)。如果能够以代码示例的形式解释它们之间的用例和区别,那将非常有帮助。
11个回答

144

关于原问题,RxJava和LiveData互为补充,相得益彰。

LiveData 在ViewModel层上表现出色,它与Android生命周期和ViewModel的紧密集成使其更具优势。而RxJava在变换方面提供了更多的功能(正如@Bob Dalgleish所提到的)。

目前,我们在数据源和存储库层使用RxJava,并将其转换为LiveData(使用LiveDataReactiveStreams)在ViewModels中(在向活动/片段公开数据之前) - 对此方法感到非常满意。


11
如果我们理解正确的话,LiveData 只适用于针对 Android UI 的实现。如果我们只是构建一个通用应用程序并与其他平台共享这个架构,那么 RxJava 比 LiveData 更合适? - IgorGanapolsky
1
@IgorGanapolsky 你在通用应用程序中使用哪种语言/框架? - kzotin
4
您能否提供LiveDataReactiveStreams的任何工作示例? - Pawan
3
@kzotin,你其实不需要使用observeOn,因为LiveDataReactiveStreams会通过调用LiveData.postValue()自动实现这一点。同时,在一般情况下,使用subscribeOn也不能保证起到任何效果。 - arekolek
2
我在Big Nerd Ranch上发现了一篇很棒的文章Where RxJava meets LiveData - Mohammad Reza Khahani
显示剩余5条评论

134

Android LiveData是原始观察者模式的一种变体,增加了活动/非活动转换。因此,它在范围上非常有限。

使用Android LiveData中描述的示例,创建一个类来监视位置数据,并根据应用程序状态进行注册和注销。

RxJava提供的运算符更加通用。假设这个可观察对象将提供位置数据:

Observable<LocationData> locationObservable;

使用 Observable.create() 来构建可观察对象,将回调操作映射进去。当可观察对象被订阅时,回调被注册,当它被取消订阅时,回调被注销。这个实现看起来与示例中提供的代码非常相似。

我们还假设你有一个可观察对象,在应用程序活动时会发出 true:

Observable<Boolean> isActive;

您可以通过以下方式提供LiveData的所有功能:

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

switchMap()操作符将当前位置作为流提供,如果应用程序不活动,则不提供任何内容。一旦您拥有了liveLocation可观察对象,使用RxJava操作符可以执行很多操作。我最喜欢的例子是:

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

只有当位置发生变化且位置是有趣的时候,它才会执行该操作。您可以创建类似的操作,结合时间运算符来确定速度。更重要的是,您可以使用RxJava运算符对操作发生的线程进行详细控制,包括主线程、后台线程或多个线程。

RxJava的重点在于将控制和定时结合成一个单一的宇宙,使用库提供的操作,甚至是您提供的自定义操作。

LiveData仅涉及该宇宙的一小部分,相当于构建liveLocation


2
谢谢,LiveData文档似乎不再提供位置示例。这里有更多有趣的内容(包括位置示例):http://androidkt.com/livedata/ - Daniel Wilson
5
@DanielWilson,该链接不再可用。 - Tura
1
兄弟,我记不得那个链接里是什么了 :D 我喜欢Mark Allison的实时数据示例代码:https://blog.stylingandroid.com/architecture-components-livedata/ - Daniel Wilson
4
RxJava的核心在于将控制和时间结合到一个单一的世界中,使用来自库提供的操作或甚至是你提供的自定义操作。但LiveData不是已经具备生命周期感知能力了吗?如果我们要使用Rx,难道不需要处理生命周期变化吗? - Sparker0i
@Sparker0i 在这里说得对。 RxJava 不具备生命周期感知能力。我们必须手动处理。而在 LiveData 中,生命周期已经被处理了。 - Aks4125
显示剩余3条评论

124

LiveData和RxJava之间存在许多差异:

  1. LiveData不是一个,而在RxJava中几乎所有东西(真的几乎所有)都是一个
  2. LiveData是一个可观察的数据持有者类。与普通的可观察对象不同,LiveData具有生命周期感知能力,这意味着它尊重其他应用程序组件(如活动、片段或服务)的生命周期。这种意识确保LiveData只更新处于活动生命周期状态的应用程序组件观察者。
  3. LiveData是同步的,因此你不能像使用RxJava一样异步执行代码块(网络调用、数据库操作等)。
  4. 最佳实践是在业务逻辑层(包括存储库及其以外的任何地方)使用RxJava,而在表示层使用LiveData。这样,您就可以为业务逻辑获得转换和流功能,为UI获得生命周期感知操作。
  5. LiveData和RxJava互补,如果一起使用的话。我的意思是,使用RxJava完成所有任务,然后在更新UI时,可以像下面的代码一样将Observable更改为LiveData。因此,您的视图(UI)观察ViewModel中的LiveData,在那里,您的LiveData仅是不可变的MutableLiveData (或MutableLiveData是可变的LiveData)。
  6. 所以问题在于,为什么要首先使用LiveData? 如下代码所示,您将RxJava中的响应存储到MutableLiveData(或LiveData)中,而LiveData具有生命周期感知能力,因此从某种意义上说,你的数据也具有生命周期感知能力。现在,想象一下当您的数据本身知道何时更新UI,何时不需要更新的可能性。
  7. LiveData没有历史记录(只有当前状态)。因此,不应将LiveData用于聊天应用程序。
  8. 当您将LiveData与RxJava一起使用时,就不需要像MediatorLiveDataSwitchMap等内容了。它们是流控制工具,而RxJava在这方面更加出色。
  9. 将LiveData视为一个数据持有者,并没有其他作用。我们还可以说,LiveData是生命周期感知型的消费者。
    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();
         }
    }

8
将LiveData视为数据持有者,不要将其看作其他任何东西。==> 是的 - Lou Morda
4
不错的例子。你忘记声明可清理对象并且在onCleared中清除它们会更好。 - Snicolas
能否请您解释一下LiveData如何同步?据我所知,我们可以将LiveData对象发送到另一个线程,然后该线程可以使用postValue方法发布值,而观察者则可以在主线程中监听到这个值。 - Hitesh Bisht
LiveData 的生命周期不是一个很大的区别吗?你需要 1. 描述你的管道需要做什么以及你的最终结果,2. 在“observe”子句中订阅结果,然后 3. 只有在您的生命周期状态允许时,管道才会被操作。 - Srg
3
我认为在网络调用中使用 Rx 是一种反模式。大多数情况下并不是流。我知道这很惊讶,但它们确实不是。那些以 Rx 为生命之本的人会说它们是流,但事实上并非如此。除非你使用订阅,否则一个网络调用只有一个结果。而只有一个结果的流是没有意义的。这就像因为你有一把锤子就把所有东西都当成钉子一样愚蠢。 - funct7
显示剩余3条评论

33
事实上,LiveData并不是与RxJava本质上不同的工具,那么为什么要将其引入架构组件,而RxJava仅需在一个CompositeDispoable对象中存储所有可观察对象的订阅,并在ActivityonDestroy()FragmentonDestroyView()中使用一行代码即可处理生命周期?
我曾经用RxJava和LiveData分别构建了一个电影搜索应用,回答了这个问题here
简而言之,是的,它可以,但需要首先重写相关生命周期方法,除了基本的生命周期知识。这对某些人可能仍然没有意义,但事实是,根据Google I/O 2018 Jetpack sessions之一,许多开发人员认为生命周期管理很复杂。由于未处理生命周期依赖关系而导致的崩溃错误可能是另一个迹象,即使熟悉生命周期的开发人员也会忘记在应用程序中使用每个Activity / Fragment时都应该注意到这一点。在大型应用程序中,这可能成为一个问题,尽管它可能对生产力产生负面影响。
引入LiveData后,预计会有更多的开发人员采用MVVM模式,而无需理解生命周期管理、内存泄漏和崩溃等问题。尽管我毫不怀疑LiveData在功能和给开发人员带来的能力方面无法与RxJava相比,但是响应式编程和RxJava对于许多人来说是一个难以理解的概念和工具。另一方面,我认为LiveData并不意味着要取代RxJava——它根本无法做到——而只是一个非常简单的工具,用于处理许多开发人员遇到的有争议的普遍问题。
** 更新 ** 我添加了一篇新文章here,其中解释了如何错误使用LiveData可能导致意外结果。在这些情况下,RxJava可以提供帮助。

2
为什么要引入LiveData,当RxJava可以通过将所有订阅存储在CompositeDisposable中,并在ActivityonDestroy()中进行处理,从而轻松管理生命周期。实际上,LiveData会在onStop中处理清理工作。 - arekolek
根据我的理解,即使要处理CompositeDisposable,我们也需要重写生命周期方法。但是在LiveData中,所有内容都包含在单行代码中。因此,我们可以节省至少20行代码。 - Suresh
我们可以定义一个baseFragment,并定义Disposable[] subscriptions()方法,让所有派生的fragment重写该方法,在onCreateView中调用此方法并将返回值添加到CompositeDisposable中,在onDestroyView中处理该对象,不再遗漏。 - android2013
不仅仅是处理垃圾回收。使用RxJava,您必须在onStop中进行处理,然后在onStart / onResume中重新订阅,处理配置更改以及执行其他一些操作。这就是为什么使用RxJava会导致如此多的崩溃。LiveData可以处理所有这些问题,但不像RxJava那样灵活。 - owl777

27

如您所知,在反应式生态系统中,我们有一个Observable来发出数据并有一个Observer订阅(获取通知)这个Observable的发射,这就是所谓的观察者模式的工作方式。 Observable“喊出”一些东西,观察者被通知在给定的时刻可知道Observable喊出了什么。

LiveData视为一个Observable,它允许您管理处于active状态的Observers。换句话说,LiveData是一个简单的Observable,同时也负责生命周期。

但让我们看看您请求的两种代码情况:

A) LiveData

B) RXJava

A)这是LiveData的基本实现

1) 通常会在ViewModel中实例化LiveData以保持方向更改(您可以拥有只读的LiveData或可写的MutableLiveData,因此通常从类外公开LiveData)

2) 在Main Activity的OnCreate方法中(而不是ViewModel),您会“订阅”一个Observer对象(通常是onChanged方法)

3) 启动observe方法以建立链接

首先是ViewModel(拥有业务逻辑)

class ViewModel : ViewModel() { //Point 1

    var liveData: MutableLiveData<Int> = MutableLiveData()

}

这是MainActivity(尽可能简单)

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)这是RXJava的基本实现

1) 声明Observable

2) 声明Observer

3) 使用Observer订阅Observable

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);
       }
    });

特别是 LiveDataLifecycle 和通常与 ViewModel(正如我们所见)架构组件一起使用。事实上,当将 LiveData 与 ViewModel 结合使用时,您可以 实时更新 Observer 中的每个更改,以便在需要的位置实时管理事件。强烈建议了解生命周期概念及其相关对象LifeCycleOwner / LifeCycle,同时建议查看Transformations,如果想要在现实场景中实现LiveData。在这里,您可以从 commonsware 中找到一些用例。

总之,基本上 LiveData 是简化版的 RXJava,一种优雅的方式可以观察多个组件的变化,而无需在组件之间创建显式的所谓依赖关系规则,因此您可以更轻松地测试代码并使其更易读。 RXJava 允许您做 LiveData 的事情,还可以做更多的功能。由于 RXJava 具有扩展功能,因此您既可以为简单情况使用 LiveData,也可以利用 RXJava 的所有功能继续使用 Android 架构组件,例如ViewModel,当然这意味着 RXJava 可能会复杂得多,想象一下它拥有数百个操作符,而 LiveData 目前只有 SwitchMap 和 Map。

RXJava 2 版本是一种革命性的库,为面向对象范式添加了所谓的函数式方式来管理程序流程。


4

LiveData是由安卓团队开发的安卓架构组件的一部分。

通过使用LiveData和其他架构组件,架构组件会处理内存泄漏和其他类似问题。由于它是由安卓团队开发的,因此最适合安卓使用。他们还提供更新以处理新版本的安卓。

如果您只想在安卓应用程序开发中使用,那么请选择安卓架构组件。否则,如果您想使用其他Java应用程序,如Web应用程序、桌面应用程序等,请使用RxJava。


我尝试澄清你的回答。如果我与你最初的意图有任何冲突,请随意编辑。但是,如果你这样做,请尽量使其比初始版本更清晰。你回答的最后一部分实在让人费解。 - Zoe stands with Ukraine

2
  • LiveData部分等同于Rx Subject或SharedRxObservable

  • LiveData管理订阅的生命周期,但是Rx Subject的订阅必须手动创建和处理

  • LiveData没有终止状态,但是Rx Subject有OnError和OnCompleted


2

LiveData是一个数据持有者,仅此而已。我们也可以说LiveData是生命周期感知的消费者。强烈建议了解生命周期概念和相关对象LifeCycleOwner/LifeCycle,您可以获得业务逻辑的转换和流能力,并为您的UI提供生命周期感知操作。

Rx是一个强大的工具,可以以优雅的声明式风格解决问题。它处理业务方面的选项或服务API操作。


1

将LiveData与RxJava进行比较就像将苹果与水果沙拉进行比较。

将LiveData与ContentObserver进行比较就像将苹果与苹果进行比较。LiveData有效地取代了ContentObserver,具有生命周期感知功能。

将RxJava与AsyncTask或任何其他线程工具进行比较就像将水果沙拉与橙子进行比较,因为RxJava不仅帮助处理线程问题。


0
我的简单回答是不要使用RxJava。它过于复杂且被滥用。对于所有使用RxJava的项目,它们很难维护和调试。RxJava异步执行操作,使用其中的线程来分派请求,但通常这完全没有必要,如果需要的话,Kotlin协程在99%的情况下做得更好。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接