admin管理员组

文章数量:1594235

As an Android Developer, you can be able use ViewModel concept in your architecture to communicate among various views of your application. However, the situation could be more complicated because of a large number of data as well as rotation of your screen. As a result, Google has introduced the concept of LiveData in Android development for tackling these issues. Basically, LiveData is an observable data holder class, which is also lifecycle aware. This essay will discuss some best practices in using Android LiveData.

作为Android开发人员,您可以在体系结构中使用ViewModel概念在应用程序的各种视图之间进行通信。 但是,由于大量数据以及屏幕旋转,情况可能会更加复杂。 结果,Google在Android开发中引入了LiveData的概念来解决这些问题。 基本上,LiveData是可观察的数据持有者类,它也是生命周期感知的。 本文将讨论使用Android LiveData的一些最佳做法。

简介与概述 (Introduction and Overview)

Basically, LiveData is an observable data holder class, which is also lifecycle aware. As you know, in our Object-Oriented programming, probably the easiest way of communicating one component and another is by having a reference from one object to another, and just call this reference directly. However, this might have some problematic issues in Android because components in Android have different lifecycles and lifespans. A simple issue like device rotation can lead to recreate the activity. As a result, as you probably know that having a reference to the activity in this ViewModel would be an inappropriate idea because it leads to memory leaks, even crashes with null pointer exceptions. So, instead of having a reference to the activity in the ViewModel, trying to have a reference to the ViewModel in the activity could be a better idea. So, the questions is how do we can communicate? Or, how do we send data from the ViewModel to the activity? So, to achieve this goal, we should let let the activity observe the ViewModel. This means for accomplishing that purpose Observable LiveData could be used.

基本上,LiveData是可观察的数据持有者类,它也是生命周期感知的。 如您所知,在我们的面向对象的编程中,一种组件与另一种组件之间进行通信的最简单方法可能是从一个对象到另一个对象建立引用,然后直接调用该引用。 但是,这可能会在Android中出现一些问题,因为Android中的组件具有不同的生命周期和寿命。 设备旋转之类的简单问题可能导致重新创建活动。 结果,您可能知道在此ViewModel中引用活动是不恰当的主意,因为它会导致内存泄漏,甚至会因空指针异常而崩溃。 因此,与其在ViewModel中引用活动,不如在活动中引用ViewModel可能是一个更好的主意。 那么,问题是我们如何沟通? 或者,我们如何将数据从ViewModel发送到活动? 因此,为了实现此目标,我们应该让活动观察ViewModel。 这意味着可以使用Observable LiveData来实现该目的。

LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active lifecycle state.

LiveData是可观察的数据持有者类。 与常规的可观察数据不同,LiveData具有生命周期感知功能,这意味着它尊重其他应用程序组件(例如活动,片段或服务)的生命周期。 这种意识确保LiveData仅更新处于活动生命周期状态的应用程序组件观察者。

了解Android LiveData (Understanding Android LiveData)

As a matter of fact, in the ViewModel, we expose our LiveData. Then, in our activity, we make the actual subscription by calling the observed method on the Observable. The first parameter is something called a lifecycle owner, and the second parameter is an observer. This is what is called whenever the Observable, the LiveData’s value is changed.

事实上,在ViewModel中,我们公开了LiveData。 然后,在我们的活动中,我们通过在Observable上调用被观察的方法来进行实际预订。 第一个参数是所谓的生命周期所有者,第二个参数是观察者。 每当可观察值,LiveData的值更改时,这就是所谓的。

All in all, you want to reference an object in the larger scope like a ViewModel, from an object in a smaller scope like an activity. However, when you observe something, it has to keep a reference back to you to be able to call it. So, Obviously, there is a reference, but why is this not a problem with LiveData? The answer is that LiveData is a lifecycle-aware component. This means to able to observe a LiveData, you have to provide the lifecycle. Then, when you provide this lifecycle, it basically maintains your subscription for you for free. So, if you are observer’s lifecycle is not in an appropriate state, it is not going to call you back. Also, when your activity of fragment is destroyed, it is going to remove the subscription automatically for you. Thus, you do not have the burden of maintaining the subscription. Another key point is that your LiveData observer will just only be called if it is between started state and before it is stopped. This makes sure you do not need to care about some issues like fragment transactions. Once you receive an observer value, you know you are in an appropriate state.

总而言之,您要从较小范围(如活动)的对象中引用较大范围的对象(如ViewModel)。 但是,当您观察到某些东西时,它必须保留一个引用给您,以便能够调用它。 因此,显然有一个参考,但是为什么LiveData不会出现此问题? 答案是LiveData是生命周期感知的组件。 这意味着要观察LiveData,必须提供生命周期。 然后,当您提供此生命周期时,它基本上可以免费维护您的订阅。 因此,如果您的观察者的生命周期未处于适当的状态,则不会回叫您。 同样,当您的fragment活动被破坏时,它将自动为您删除预订。 因此,您没有维护订阅的负担。 另一个要点是,仅当LiveData观察者处于启动状态与停止之间之间时,才会调用它。 这样可以确保您不必担心片段事务之类的问题。 收到观察者值后,您就知道自己处于适当的状态。

Google documents Google文档提供

Perhaps, the most distinctive property of LiveData is the data holder. So, it is not a stream, but it is a value holder. This means when you set a value on the LiveData, just value is passed to the activity. In similar, if the value change, the activity receives the new updated value. At the moment, the difference happens when you change the value, when the observer is not in an active state, it has no idea. For example, while your activity is still in a background, you set the new value. Therefore, your activity still does not see this. Now, the data holder property comes, when your activity comes back, in the foreground, it receives the latest value from the ViewModel. In fact, LiveData just only cares about holding a single value, and it is the latest value indeed. This works ideally for UI because you only want to display what it is right now. On the other hand, if you are planning to process a stream of events, this is not what you are looking for. Finally, if you change the value after activity is destroyed, nothing happens.

也许,LiveData最独特的属性是数据持有者。 因此,它不是流,而是价值持有者。 这意味着当您在LiveData上设置一个值时,仅将值传递给活动。 同样,如果值更改,活动将接收新的更新值。 目前,差异发生在您更改值时,当观察者不处于活动状态时,它根本不知道。 例如,当您的活动仍在后台时,您可以设置新值。 因此,您的活动仍然看不到。 现在,数据持有者属性出现,当您的活动返回时,在前台,它将从ViewModel接收最新值。 实际上,LiveData仅关心持有一个值,而这确实是最新值。 这非常适合UI,因为您只想显示当前状态。 另一方面,如果您打算处理事件流,那么这不是您想要的。 最后,如果在销毁活动后更改值,则不会发生任何事情。

实施Android LiveData (Implementing the Android LiveData)

Initially, to implement LiveData in your Android projects, you should follow some steps as follows:

最初,要在Android项目中实现LiveData,应遵循以下步骤:

  1. Creating a LiveData object in ViewModel class

    在ViewModel类中创建LiveData对象

In fact, LiveData objects will usually be kept in the ViewModel class, and be accessed via a getter method. As a result, the first step is crating the LiveData object in ViewModel class. In addition, LiveData is a wrapper that can be used with any types of data like list.

实际上,LiveData对象通常将保留在ViewModel类中,并通过getter方法进行访问。 结果,第一步是在ViewModel类中创建LiveData对象。 此外,LiveData是可与任何类型的数据(如列表)一起使用的包装器。

class SampleViewModel : ViewModel() {// Create a LiveData with a String
val currentName: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}// Rest of the ViewModel...
}

2. Observing the LiveData object

2.观察LiveData对象

Now, over in your activity’s onCreate method, you will get that LiveData from the ViewModel class. This means you call observe on the LiveData.

现在,在活动的onCreate方法中,您将从ViewModel类获取该LiveData。 这意味着您在LiveData上调用了watch。

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Get the ViewModel
viewModel=ViewModelProviders.of(this).get(UserViewModel::class.java
// Rest of the onCreate method...
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Rest of the onCreate method...
// Creating the observer for updating the UI
val sampleObserver = Observer<String> { newName ->
// Update the UI, in this example, a TextView.
sampleTextView.text = newName
}
// Observe the LiveData
viewModel.currentName.observe(this, nameObserver)
}

To use LiveData in our activity along with the ViewModel wholly, after registering the Observer in the Activity, we must override the onChanged() method, and you will define the operation that will be triggered when there is a change in data. So, to get LiveData object form ViewModel as above for User object, you can do it in onCreate method as follows:

要在我们的活动中将LiveData与ViewModel一起使用,请在Activity中注册Observer之后,我们必须重写onChanged()方法,然后定义将在数据发生更改时触发的操作。 因此,要从上面的UserModel的ViewModel中获取LiveData对象,可以在onCreate方法中进行如下操作:

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
userViewModel.user.observe(this, Observer { user -> userNameTextView.text = user?.name
})
}

In above, the first argument is “this”. That means you must pass the UI, which is activity in this case. Besides, the second argument is an Observer, which is just a callback. However, if you use Data Binding library, you will not need to manually set up these observers. Thus, you can remove all the above boilerplate because the TextView’s XML references the LiveData directly in activity_main.xml.

在上面,第一个参数是“ this”。 这意味着您必须传递UI,在本例中为活动。 此外,第二个参数是一个Observer,它只是一个回调。 但是,如果使用数据绑定库,则无需手动设置这些观察器。 因此,您可以删除上述所有样板,因为TextView的XML直接在activity_main.xml中引用LiveData。

转换LiveData (Transforming LiveData)

Probably, you want to make changes to the value stored in a LiveData object before dispatching it to the observers, or you may need to return a different LiveData instance. The Lifecycle package supports the Transformation class that contains helper methods, which provide these approaches. The library provides two features, including map and switch map, but you can be able to create your own using Mediator LiveData. As you can see, LiveData is proper way to communicate a view and a ViewModel. However, if we have a third component like repository, it is also exposing LiveData. How do we make this subscription from the ViewModel? What if the Android app is even much more complicated, and the repository is also observing a data source in this case?

可能是,您想在将LiveData对象中存储的值分派给观察者之前进行更改,或者您可能需要返回其他LiveData实例。 Lifecycle软件包支持包含帮助程序方法的Transformation类,这些方法提供了这些方法。 该库提供了两个功能,包括地图和切换地图,但是您可以使用Mediator LiveData创建自己的地图。 如您所见,LiveData是传达视图和ViewModel的正确方法。 但是,如果我们有第三个组件(例如存储库),它也会公开LiveData。 我们如何从ViewModel进行订阅? 如果Android应用程序更加复杂,并且在这种情况下存储库也在观察数据源该怎么办?

Transformations.map:一对一静态转换 (Transformations.map: One-to-One static transformation)

We use a transformation’s map, which is called a one-to-one static transformation. The first parameter is the source, the LiveData source, which is the LiveData exposed by the repository. In addition, the second parameter is the transformation function.

我们使用转换的映射,这称为一对一静态转换。 第一个参数是源,即LiveData源,它是资源库公开的LiveData。 另外,第二个参数是变换函数。

val userLiveData: LiveData<User> = UserLiveData()
val userName: LiveData<String> = Transformations.map(userLiveData) {
user -> "${user.name} ${user.lastName}"
}

When you establish that transformation, the key here is that the lifecycle is automatically carried over for you. So, you run a transformation of couple of LiveData. At the end, it is a LiveData that you hold onto. When someone subscribes to it, that lifecycle is automatically propagated to the inner LiveData elements without you doing anything. In short, it is completely managed by Google. Another example is that where we need to show Snackbar whenever a new user added to the database. The Snackbar shows data of a custom String with username added in it.

建立转换后,关键是生命周期将自动为您延续。 因此,您运行了几个LiveData的转换。 最后,它是您要保留的LiveData。 当有人订阅它时,该生命周期将自动传播到内部LiveData元素,而无需您进行任何操作。 简而言之,它完全由Google管理。 另一个示例是,每当有新用户添加到数据库时,我们都需要显示Snackbar。 小吃栏显示自定义字符串的数据,并在其中添加了用户名。

Transformations.switchMap:一对一动态转换 (Transformations.switchMap: One-to-one dynamic transformation)

Imagine you have an Android application where you have a user measure that keeps the logged in user ID somewhere like in a disk. Besides, whenever that logged in user ID, when you grab it, you require to communicate to your user repository to obtain the real user object. So, that probably leads to use the database and the server to return this user object. However, that repository returns your LiveData as well because your object might change. It may return you the cache one while it updates from the server. So, you are in a condition where you have a LiveData of a logged in user ID and a LiveData of a user. Furthermore, you require to chain these issues. As a result, map works if you are chaining from an ID to a user, but how do we change from an ID to a LiveData of a user? In this case, you will need switch map as a transformation function.

假设您有一个Android应用程序,其中有一个用户度量,该度量将登录的用户ID保留在磁盘中的某个位置。 此外,无论何时登录的用户ID,当您获取它时,都需要与用户存储库进行通信以获得真实的用户对象。 因此,这可能导致使用数据库和服务器返回此用户对象。 但是,该存储库也会返回您的LiveData,因为您的对象可能会更改。 从服务器更新时,它可能会向您返回一个缓存。 因此,您处于一种状态,即具有一个已登录用户ID的LiveData和一个用户的LiveData。 此外,您需要链接这些问题。 结果,如果您从一个ID链接到一个用户,则map可以工作,但是如何从一个ID更改为一个用户的LiveData? 在这种情况下,您将需要开关图作为转换功能。

private fun getUser(id: String): LiveData<User> {
...
}
val userId: LiveData<String> = ...
val user = Transformations.switchMap(userId) { id -> getUser(id) }

Every time that user ID changes, it calls your function. You give it a new LiveData. It unsubscribes from the previous LiveData you returned, and then subscribes to the new one. However, it is still lifecycle-aware, and you get all the benefits of using LiveData. Another example where you need to search user by username and show the result inside the RecyclerView.

每次用户ID更改时,它都会调用您的函数。 您给它一个新的LiveData。 它从您返回的上一个LiveData取消订阅,然后订阅新的LiveData。 但是,它仍然是生命周期感知的,您可以获得使用LiveData的所有好处。 另一个示例,您需要按用户名搜索用户并在RecyclerView中显示结果。

MediatorLiveData:一对多依赖 (MediatorLiveData: On-to-many dependency)

If you want to make your own custom data transformations, you should consider the MediatorLiveData class. MediatorLiveData includes methods to add and remove source LiveData objects. Therefore, you can combine and propagate events form all these sources downstream.

如果要进行自己的自定义数据转换,则应考虑MediatorLiveData类。 MediatorLiveData包括添加和删除源LiveData对象的方法。 因此,您可以从所有这些下游源合并和传播事件。

使用Android LiveData的一些不当想法 (Some inappropriate ideas in using Android LiveData)

1. Storing enormous objects across Transformations

1.在转换中存储大量对象

For instance, when you make a web request, it returns you a giant JSON. Next, you convert it to your objects. Using your LiveData transformation for performing that purpose is not a suitable idea because LiveData is a value holder. In other words, the long string you fetch from your server is going to stay in memory. Thus, do not use LiveData for some scenarios like this.

例如,当您发出Web请求时,它会返回一个巨大的JSON。 接下来,将其转换为对象。 使用LiveData转换来实现该目的是不合适的,因为LiveData是值的持有者。 换句话说,您从服务器获取的长字符串将保留在内存中。 因此,请勿在某些情况下使用LiveData。

2. Sharing instances of LiveData

2.共享LiveData实例

For instance, you have concluded incorrectly that your repository is a Singleton and there is just only one observer, and you can just share a single LiveData. To be specific, there is this case in Android, where two activities are going to be active at the same time. So, imagine activity one observes item number one and activity two observes item number two. When we load activity two, it is going to load data for item two because they are sharing the same LiveData, activity one is also going to receive that data. As a result, when it is in the middle of an animation, you will observe a flash and glitch. Obviously, that is an extremely unacceptable user experience. The solution is that you should create a LiveData each time because it is very lightweight indeed.

例如,您错误地得出结论,您的存储库是一个Singleton,并且只有一个观察者,并且您只能共享一个LiveData。 具体来说,在Android中会出现这种情况,其中两个活动将同时处于活动状态。 因此,假设活动一观察到第一项,活动二观察到第二项。 当我们加载活动2时,它将加载项目2的数据,因为它们共享相同的LiveData,活动1也将接收该数据。 结果,当它在动画中间时,您将观察到闪烁和毛刺。 显然,这是极其无法接受的用户体验。 解决方案是您应该每次创建一个LiveData,因为它确实非常轻巧。

3. Another best practice is that if you require a number of operators or streams in your Android project, you must use RxJava.

3.另一个最佳实践是,如果您在Android项目中需要多个运算符或流,则必须使用RxJava

4. If your operations are not about UI or lifecycle, you must use callback interfaces. For instance, when you want to synchronize the user’s location to your back-end service, there are no UI and lifecycle.

4.如果您的操作与UI或生命周期无关,则必须使用回调接口。 例如, 当您要将用户的位置同步到后端服务时, 没有UI和生命周期 e。

5. Eventually, if you have one-shot operation chaining, use Coroutines. For example, you want to fetch some data and convert data, or you write into your database, load back, and return it. In fact, LiveData works efficiently as the latest layer for your UI.

5.最终,如果您具有一次性操作链接 ,请使用Coroutines 。 例如,您要获取一些数据并转换数据,或者您要写入数据库,然后加载并返回。 实际上,LiveData可以有效地用作UI的最新层。

结论 (In conclusion)

In fact, Google has introduced the concept of LiveData in Android development for tackling some controversial issues like device rotation. Basically, LiveData is an observable data holder class, which is also lifecycle aware. This considered some best practices in using Android LiveData.

实际上,Google在Android开发中引入了LiveData的概念,以解决诸如设备旋转之类的一些有争议的问题。 基本上,LiveData是可观察的数据持有者类,它也是生命周期感知的。 这考虑了使用Android LiveData的一些最佳做法。

翻译自: https://medium/kayvan-kaseb/some-best-practices-in-using-android-livedata-47d789d10185

本文标签: 做法androidlivedata