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

Posted

技术标签:

【中文标题】何时在 Android 中使用 RxJava,何时使用 Android 架构组件中的 LiveData?【英文标题】:When to use RxJava in Android and when to use LiveData from Android Architectural Components? 【发布时间】:2018-02-28 23:26:27 【问题描述】:

我没有理由在 android 中使用 RxJava 和从 Android Architectural Components 中使用 LiveData。如果用示例说明两者之间的用例和差异以及解释两者之间差异的示例示例,那将非常有帮助两者兼而有之。

【问题讨论】:

你找到好的理由了吗?我也想知道... 【参考方案1】:

关于最初的问题,RxJava 和 LiveData 相得益彰。

LiveData 在 ViewModel 层上大放异彩,它与 Android 生命周期和ViewModel 紧密集成。 RxJava 提供了更多的转换功能(如@Bob Dalgleish 所述)。

目前,我们在数据源和存储库层中使用RxJava,它在 ViewModels 中转换为LiveData(使用LiveDataReactiveStreams)(在将数据暴露给活动/片段之前)——对这种方法非常满意。

【讨论】:

如果我们对您的理解正确,那么 LiveData 仅对 Android UI 特定的实现有用。如果我们只是用 Clean Architecture 构建一个通用应用程序,并与其他平台共享该架构,那么 RxJava 是否比 LiveData 更适合? @IgorGanapolsky 通用应用程序使用什么语言/框架? 你能在你的回答中推荐任何 LiveDataReactiveStreams 的工作示例吗? @kzotin 你不需要observeOnLiveDataReactiveStreams 无论如何通过调用LiveData.postValue() 来做到这一点。并且不能保证您的 subscribeOn 总体上会产生任何影响。 我在大书呆子牧场Where RxJava meets LiveData找到这篇很棒的文章【参考方案2】:

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

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

RxJava 提供了更通用的运算符。假设这个 observable 将提供位置数据:

Observable<LocationData> locationObservable;

observable 的实现可以使用Observable.create() 来映射回调操作。当 observable 被订阅时,回调被注册,当它被取消订阅时,回调被取消注册。该实现看起来与示例中提供的代码非常相似。

我们还假设您有一个在应用程序处于活动状态时发出 true 的 observable:

Observable<Boolean> isActive;

那么你可以通过以下方式提供LiveData的所有功能

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

switchMap() 运算符要么将当前位置作为流提供,要么在应用程序未处于活动状态时不提供任何内容。一旦你有了liveLocation observable,你可以使用 RxJava 操作符来做很多事情。我最喜欢的例子是:

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

这只会在位置发生变化并且位置有趣时才执行操作。您可以创建类似的操作 结合时间算子来确定速度。更重要的是,您可以使用 RxJava 运算符详细控制操作是在主线程、后台线程还是多个线程中发生。

RxJava 的重点在于它将控制和计时结合到一个单一的世界中,使用库提供的操作,甚至是您提供的自定义操作。

LiveData 只处理该宇宙的一小部分,相当于构建liveLocation

【讨论】:

谢谢,LiveData 文档似乎不再引用位置示例。这里有更多有趣的点(带有位置示例):androidkt.com/livedata @DanielWilson 该链接不再可用。 伙计,我不记得 wtf 在那个链接上:D 我喜欢 Mark Allison 的实时数据示例代码:blog.stylingandroid.com/architecture-components-livedata 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. 但不知道 LiveData 生命周期。如果我们要使用 Rx,难道我们不需要处理生命周期的变化吗? @Sparker0i 明白了。 RxJava 不支持生命周期。我们必须手动处理。就像在 LiveData 中一样,它已经处理了生命周期。【参考方案3】:

LiveData 和 RxJava 有很多不同之处:

    LiveData 不是 STREAM,而在 RxJava 中一切(字面意思)都是 STREAM。 LiveData 是一个可观察的数据持有者类。与常规的 observable 不同,LiveData 具有生命周期感知能力,这意味着它尊重其他应用程序组件的生命周期,例如活动、片段或服务。这种意识可确保 LiveData 仅更新处于活动生命周期状态的应用组件观察者。 LiveData 是同步的,因此您不能像使用 RxJava 那样仅使用 LiveData 异步执行一段代码(网络调用、数据库操作等)。 要充分利用这对组合的最大优势,您可以做的最好的事情就是将 RxJava 用于您的业务逻辑(网络调用、数据操作等,Repository 内外发生的任何事情),并将 LiveData 用于您的表示层。这样,您就可以获得业务逻辑的转换和流功能以及 UI 的生命周期感知操作。 LiveData 和 RxJava 相互补充如果一起使用。我的意思是,用 RxJava 做所有事情,最后当你想更新 UI 时,做一些类似下面给出的代码来将你的 Observable 更改为 LiveData。因此,您的视图 (UI) 会观察 ViewModel 中的 LiveData,其中您的 LiveData 只不过是不可变的 MutableLiveData(或 MutableLiveData 是可变的 LiveData)。 所以这里的问题是,你为什么要首先使用 LiveData? 正如您在下面的代码中看到的,您将来自 RxJava 的响应存储到 MutableLiveData(或 LiveData),并且您的 LiveData 是生命周期感知的,因此在某种程度上,您的数据是生命周期感知的。现在,想象一下当您的数据本身知道何时以及何时不更新 UI 时的可能性。 LiveData 没有历史记录(只有当前状态)。因此,您不应将 LiveData 用于聊天应用程序。 当您将 LiveData 与 RxJava 一起使用时,您不需要像 MediatorLiveDataSwitchMap 等东西。它们是流控制工具,而 RxJava 在这方面要好很多倍。 将 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();
         
    

【讨论】:

将 LiveData 视为数据持有者,仅此而已。 ==> 是的 很好的例子。您忘记声明一次性物品,最好在onCleared 中清除它们。 你能解释一下livedata是如何同步的吗?据我所知,我们可以将 Livedata 对象发送到另一个线程,然后该线程可以后置值,观察者可以在 MainThread 中收听。 如果你再次阅读我写的内容,这意味着你不能像使用 RxJava 一样使用 LiveData 在另一个线程上工作(是的,即使在那里我也使用“just”) 我认为使用 Rx 进行网络调用是一种反模式。大多数东西不是流。我知道。这是一个令人震惊的。但他们不是。围绕 Rx 建立生活的人说他们是,但实际上不是。除非您使用订阅,否则网络调用只有一个结果。具有单一结果的流只是愚蠢的。这就像把所有东西都当作钉子,因为你有一把锤子。【参考方案4】:

事实上,LiveDataRxJava 并没有本质上不同的工具,那么为什么当 RxJava 可以通过将所有对 observables 的订阅存储在 @987654327 中来轻松管理生命周期时,它作为架构组件引入@ 对象,然后仅使用一行代码将它们放置在ActivityonDestroy()FragmentonDestroyView() 中?

我已经通过使用 RxJava 构建一个电影搜索应用程序,然后使用 LiveData here 完全回答了这个问题。

但简而言之,是的,它可以,但是除了具备基本的生命周期知识之外,还需要首先覆盖相关的生命周期方法。这对某些人来说可能仍然没有意义,但事实是,根据Jetpack sessions in Google I/O 2018 之一的说法,许多开发人员发现生命周期管理很复杂。由于不处理生命周期依赖而导致的崩溃错误可能是一些开发人员即使了解生命周期也忘记在他们在应用程序中使用的每个 Activity / Fragment 中处理这一点的另一个迹象。在大型应用程序中,这可能会成为一个问题,尽管它可能会对生产力产生负面影响。

底线是,通过引入LiveData,预计会有更多的开发人员采用 MVVM,甚至无需了解生命周期管理、内存泄漏和崩溃。尽管我毫不怀疑LiveData 在功能和赋予开发人员的力量方面无法与RxJava 相提并论,但反应式编程和RxJava 对于许多人来说是一个难以理解的概念和工具。另一方面,我不认为LiveData 可以替代RxJava——它根本不能——而是一个非常简单的工具,用于处理许多开发人员遇到的有争议的普遍问题。

** 更新 ** 我添加了一篇新文章 here,我在其中解释了滥用 LiveData 如何导致意外结果。 RxJava 可以在这些情况下进行救援


【讨论】:

“为什么当 RxJava 可以通过将所有订阅存储在 CompositeDispoable 中然后将它们释放到 Activity 的 onDestroy() 中轻松管理生命周期时引入它” - LiveData 将在 @987654339 中释放@其实 @arekolek 据我了解:即使要处理 CompositeDispoable,我们也已经覆盖了生命周期方法。但在实时数据中,所有数据都将包含在单行代码中。所以我们至少节省了 20 行代码。 我们可以定义一个 baseFragment 并定义 Disposable[] subscriptions() 方法被所有派生的 Fragment 覆盖,在 onCreateView 中调用此方法并将返回值添加到 CompositeDisposable 中,在 onDestroyView 中进行处理,不要再忘记了。 这不仅仅是关于处置。使用 RxJava,您必须在 onStop 处进行处理,然后在 onStart/onResume 中再次订阅,处理配置更改,以及做很多其他事情。这就是为什么使用 RxJava 会发生这么多崩溃的原因。 LiveData 可以处理所有这些,但不如 RxJava 灵活。【参考方案5】:

您可能知道,在响应式生态系统中,我们有一个发出数据的 Observable 和一个订阅(收到通知)此 Observable 发射的 Observer,这并不奇怪工作所谓的观察者模式。一个 Observable “呼喊”某事,Observer 会收到通知,Observable 在给定时刻呼喊某事。

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

但是让我们看看你要求的两个代码案例:

A) 实时数据

B) RXJava

A)这是 LiveData 的基本实现

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

2) 在 Main Activity(不是 ViewModel)的 OnCreate 方法中 你“订阅”了一个 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) 你声明了一个观察者

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 中的每次更改,以便在需要的地方实时管理事件。使用LiveData强烈建议了解lifecycle的概念和相关对象LifeCycleOwner/LifeCycle,如果你想在现实生活场景中实现LiveData,我建议你看看Transformations .在这里您可以找到来自伟大的commonsware 的一些用例。

总结基本上LiveData是一个简化的RXJava,这是一种观察多个组件变化的优雅方式,无需在组件之间创建显式的所谓依赖规则,以便您可以更轻松地测试代码并使其更具可读性。 RXJava,允许你做 LiveData 的事情等等。由于 RXJava 的扩展功能,您既可以将 LiveData 用于简单的案例,也可以利用 RXJava 的所有功能继续使用 Android 架构组件作为ViewModel,当然这意味着RXJava 可能要复杂得多,想想有数百个运算符,而不是 LiveData 的 SwitchMap 和 Map(目前)。

RXJava 版本 2 是一个彻底改变了面向对象范式的库,添加了一种所谓的函数式方法来管理程序流。

【讨论】:

【参考方案6】:

LiveData 是 android 团队开发的 android 架构组件的子集。

使用实时数据和其他架构组件,内存泄漏和其他类似问题由架构组件处理。由于它是由android团队开发的,所以它是最好的android。它们还提供处理新版本 Android 的更新。

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

【讨论】:

我试图澄清你的答案。如果我与您的原始意图有任何冲突,请随时编辑。如果你这样做了,请尽量使它比最初的修订更清楚。老实说,您回答的最后一部分没有意义。【参考方案7】:

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

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

【讨论】:

【参考方案8】:

LiveData 部分等于 Rx Subject 或 SharedRxObservable

LiveData 管理订阅的生命周期,但 Rx 主题 订阅应手动创建和处理

LiveData 没有终止状态,但 Rx 主题有 OnError 和 OnCompleted

【讨论】:

【参考方案9】:

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

将 LiveData 与 ContentObserver 进行比较,您将苹果与苹果进行比较。 LiveData 实际上是 ContentObserver 的生命周期感知替代品。

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

【讨论】:

以上是关于何时在 Android 中使用 RxJava,何时使用 Android 架构组件中的 LiveData?的主要内容,如果未能解决你的问题,请参考以下文章

Android 数据存储,何时使用 Sqlite,何时使用 JSON,Linq 替代方案

在 Android M 中确定应用何时退出空闲模式

如何检测何时在 Android 中设置了新警报

Android:检测 ScrollView 何时停止滚动

Android:如何检测滚动何时结束

何时使用“?android”或“@android”?