livedata
重点 (Top highlight)
Architecture components are common for Android developers these days. For a long time, everyone has been using one or other architecture components to meet their requirements. LiveData is one of the most important of these components. In this piece, we discuss LiveData, how it’s used, and its importance.
如今,架构组件对于Android开发人员来说很常见。 长期以来,每个人都在使用一个或其他体系结构组件来满足他们的要求。 LiveData是这些组件中最重要的组件。 在本文中,我们讨论了LiveData,如何使用它以及它的重要性。
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/6a86686ee70b509b8289b76b4d33dbde.png)
问题 (Problem)
Previously before architecture components and Rx Java do you remember how we passed the results or callbacks to the UI thread
? Primarily, with interfaces.
以前,在体系结构组件和Rx Java之前,您还记得我们如何将结果或回调传递给UI thread
吗? 主要是带有接口的。
Let’s take a simple example of an application developed in MVP
. Previously, if there was an API call to be performed, we would call a method from View
layer in the Presenter
to perform a network request. Then, in that particular method, we used to write the Async task
to perform the operations. Once we receive the response we used a View
interface to communicate this response to the Main
thread so that it could update the UI.
让我们举一个用MVP
开发的应用程序的简单示例。 以前,如果要执行API调用,我们将从Presenter
View
层调用一个方法来执行网络请求。 然后,在该特定方法中,我们习惯于编写Async task
来执行操作。 收到响应后,我们将使用View
界面将此响应传达给Main
线程,以便它可以更新UI。
Here everything is tightly coupled View and Presenter and a huge number of interfaces are used for interaction between layers.
在这里,所有东西都紧密地结合在View和Presenter上,并且大量的接口用于图层之间的交互。
解 (Solution)
The solution to this came with MVVM
, but we’re not going to discuss this here. Suffice it to say that the major issue of using the interfaces
has been solved by the concept of LiveData
.
MVVM
解决方案,但我们不在这里讨论。 可以说,使用interfaces
的主要问题已由LiveData
概念解决。
什么是LiveData? (What is LiveData?)
From the documentation:
从文档中:
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仅更新处于活动生命周期状态的应用程序组件观察者。
它是如何工作的? (How does it work?)
To understand LiveData first we need to understand Observer Pattern. The observer pattern
is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.
要首先了解LiveData,我们需要了解观察者模式。 observer pattern
是一种软件设计模式,其中一个称为主题的对象会维护其依赖者的列表(称为观察者),并通常通过调用其方法之一来自动将状态更改通知他们。
In simple terms, there will be an Observer
that subscribes to the Observable
to get notified for the latest data or say state changes. Previously we used Rx Java
but here we need to maintain a list of subscriptions
and remove
them in onDestroy()
.
简单来说,会有一个Observer
,订阅的Observable
以获得有关最新数据的通知或说状态更改。 以前我们使用Rx Java
但在这里我们需要维护一个subscriptions
列表,并在onDestroy()
中将其remove
。
The main concept of LiveData
is an Observer
pattern. LiveData
is an observable
data holder class — there’s no need to request the latest data every time. While using MVVM
the communication from ViewModel
to View
is done with just LiveData
.
的 LiveData
主要概念是Observer
模式。 LiveData
是一个observable
数据持有者类-无需每次都请求最新数据。 使用MVVM
,仅使用LiveData
完成从ViewModel
到View
的通信。
From the View
activity or fragment we subscribe
to the LiveData
, passing the lifecycle owner
and Observer
. But there’s no need to maintain the list or destroy the subscriptions. As LiveData
is lifecycle-aware
it takes care of these things.
从View
活动或片段中,我们subscribe
LiveData
, 通过lifecycle owner
和Observer
。 但是,无需维护列表或破坏订阅。 由于LiveData
具有lifecycle-aware
它会照顾这些事情。
LiveData only posts the values to Observers
(activity or Fragment) if they are in a foreground
state, so that no memory leaks occur. There’s no need for us to check whether View
is alive
or not to update the UI inside the Observer
.
LiveData仅在Observers
(活动或片段)处于foreground
状态时才将其发布,这样就不会发生内存泄漏。 无需检查View
是否处于alive
来更新Observer
的UI。
We no longer need to worry about unsubscribing it onPause
or onDestroy
. Besides, once the Observer
is resumed, it would be immediately be notified of the latest data from the LiveData
.
我们不再需要担心在onPause
或onDestroy
取消订阅它。 此外,一旦Observer
恢复,将立即从LiveData
收到最新数据的LiveData
。
![Image for post](https://miro.medium.com/max/9999/1*0-Gq8UlglxwyTh38x4O4AQ.png)
The two important things that we need to understand about LiveData
are
关于LiveData
,我们需要了解的两个重要事项是
UI controller or View (an
Activity
orFragment
) will be notified every time the data changes instead of requesting the data each time fromViewModel
(Always up to date data!)每次数据更改时都会通知UI控制器或View(一个
Activity
或Fragment
),而不是每次都从ViewModel
请求数据( 始终是最新数据 !)LiveData is
lifecycle-aware
, so the view will be registered for observing those changes only if theView
(anActivity
orFragment
) is inSTARTED
orRESUMED
state and only then the LiveData will emit any items (so there will be no more crashes, lifecycle handling, memory leaks andNullPointerExceptions
due to unexisting views!)LiveData是
lifecycle-aware
,所以视图将被注册用于观察这些变化仅当View
(一个Activity
或Fragment
)是STARTED
或RESUMED
状态才把LiveData将发射的任何项目(因此将不会有更多的崩溃,生命周期处理,内存泄漏和由于不存在的视图而导致的NullPointerExceptions
!)
让我们开始编码 (Let's Start Coding)
To work with LiveData
we need to take the following steps:
要使用LiveData
我们需要执行以下步骤:
Declare dependencies in the app level
build.gradle
.在应用程序级别
build.gradle
声明依赖build.gradle
。Create an
instance
of LiveData to hold a certain type of data. This is usually done inside ViewModel class.创建LiveData
instance
以保存某种类型的数据。 这通常是在ViewModel类中完成的。Create an
Observer
object that defines theonChanged()
method, which controls what happens when the LiveData object's held data changes. You usually create anObserver
object in a UI controller, such as an activity or fragment.创建一个定义
onChanged()
方法的Observer
对象,该方法控制LiveData对象的保留数据更改时发生的情况。 通常,您可以在UI控制器中创建一个Observer
对象,例如活动或片段。Attach the
Observer
object to theLiveData
object using theobserve()
method. This method takes aLifecycleOwner
object and subscribesObserver
object to theLiveData
object so that it’s notified of changes. You usually attach theObserver
object in a UI controller, such as anactivity
orfragment
.使用
observe()
方法将Observer
对象附加到LiveData
对象。 此方法采用LifecycleOwner
对象,并将Observer
对象订阅到LiveData
对象,以便将更改通知给它。 通常,您将Observer
对象附加到UI控制器中,例如activity
或fragment
。
声明依赖 (Declare dependencies)
//Java
implementation "android.arch.lifecycle:extensions:1.0.0"
annotationProcessor "android.arch.lifecycle:compiler:1.0.0"//Kotlin with AndroidX
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
创建LiveData实例 (Creating LiveData instance)
LiveData is a wrapper that can be used to hold any type of data, including objects that implement Collection
s, such as List
. A LiveData
object is usually stored within a ViewModel
object and is accessed using a getter method.
LiveData是一个包装器,可用于保存任何类型的数据,包括实现Collection
的对象,如List
。 LiveData
对象通常存储在ViewModel
对象中,并使用getter方法进行访问。
Initially, the data in a LiveData object is not set later when we call setFirstName()
then the value of LiveData was updated.
最初,当我们调用setFirstName()
时,不会设置LiveData对象中的数据,然后更新LiveData的值。
在UI控制器中为LiveData创建观察者 (Creating an Observer for LiveData in UI controller)
Create an Activity
and observe the LiveData for any changes as shown below
创建一个Activity
并观察LiveData的任何变化,如下所示
更新LiveData值 (Update LiveData Values)
There are two ways to update a value in LiveData.
有两种方法可以更新LiveData中的值。
setValue
setValue
postValue
postValue
设定值 (setValue)
We must use the setValue(T)
method to update the LiveData
object from the main thread
. If we use setValue
from background thread then the app crashes, logging called from WongThread
exception.
我们必须使用setValue(T)
方法从main thread
更新LiveData
对象。 如果我们使用setValue
从后台线程启动,然后应用程序崩溃,并从WongThread
异常调用日志记录。
_nameLiveData.value = "something"
后值 (postValue)
If the code is executed in a worker
thread, other than the main thread, you can use the postValue(T)
method to update the LiveData
object. It can be used from any thread but preferred is from other than main thread because it’s a bit slower than setValue
.
如果代码是在worker
线程(而不是主线程)中执行的,则可以使用postValue(T)
方法更新LiveData
对象。 可以在任何线程中使用它,但首选从主线程之外的其他线程使用,因为它比setValue
慢一些。
_nameLiveData.postValue("something")
To update the LiveData value use setValue
from Main Thread
and postValue from any other thread
other than the main thread for better performance.
要更新LiveData值,请使用 setValue
从 Main Thread
和 后值 从任何其他 thread
主线程以外的其他线程以获得更好的性能。
用例 (Use case)
Say there’s an app that has to make an API call when a user opens an activity and clicks a button. After getting the response with LiveData
, we post the value to the UI controller to update the view. In this case, while the API call is in progress
, somehow the app goes into the background
state. Can you guess what happens next? Will the UI update or will the app crash?
假设有一个应用程序在用户打开活动并单击按钮时必须进行API调用。 使用LiveData
获得响应后,我们将该值发布到UI控制器以更新视图。 在这种情况下,当API调用progress
,应用程序将以某种方式进入background
状态。 你能猜出接下来会发生什么吗? 用户界面会更新还是应用崩溃?
The API call gets completed and LiveData
receives the value. However, neither the crash or the UI is updated because, as we discussed above, LiveData is lifecycle-aware
so when the API call is finished the LiveData receives the value but it doesn’t post the value to the UI controller. It will wait until the UI controller comes to foreground
state and then LiveData immediately posts the latest available value to the UI controller.
API调用完成, LiveData
接收该值。 但是,崩溃或UI均未更新,因为如上所述,LiveData可lifecycle-aware
所以 当API调用完成后,LiveData会收到该值,但不会将该值发布到UI控制器。 它将等到UI控制器进入foreground
状态,然后LiveData立即将最新的可用值发布到UI控制器。
LiveData的类型 (Types of LiveData)
We can extend LiveData<T>
and create our own custom class.
我们可以扩展LiveData<T>
并创建我们自己的自定义类。
MutableLiveData (MutableLiveData)
Code of MutableLiveData
, as per the documentation:
MutableLiveData
代码,根据文档:
MediatorLiveData (MediatorLiveData)
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/0890b5e58288eeb875b18c7e5553e23b.png)
We can merge results from different LiveData
objects into one using MediatorLiveData
. It can also be defined as the LiveData subclass, which may observe other LiveData objects and react to OnChanged
events from them.
我们可以使用MediatorLiveData
将来自不同LiveData
对象的结果合并为一个。 也可以将其定义为LiveData子类,该子类可以观察其他LiveData对象并对其中的OnChanged
事件做出React。
Suppose we have two LiveData objects emitting the number type value. One LiveData object emits values from a particular source and the other from a different source. We want to listen to the result from both of them and also want to neglect the result from the second LiveData if it is less than ten. We do this as follows:
假设我们有两个LiveData对象发出数字类型值。 一个LiveData对象从特定来源发出值,而另一个从另一个来源发出值。 我们想要听取他们两个的结果,并且还想忽略第二个LiveData的结果(如果小于十个)。 我们这样做如下:
val mediatorLiveData: MediatorLiveData<Int> = MediatorLiveData()
mediatorLiveData.addSource(stockLiveData1, Observer<Int> { it ->
mediatorLiveData.setValue(it)})
mediatorLiveData.addSource(stockLiveData1, Observer<Int> { value ->if (value > 10) {
mediatorLiveData.setValue(value)
}})
用例 (Use case)
Let’s say that we only want five values emitted by liveData
, to be merged inMediatorLiveData
. Then, after those five values, we can stop listening to liveData
and remove it as a source:
假设我们只希望将liveData
发出的五个值合并到MediatorLiveData
。 然后,在这五个值之后,我们可以停止监听liveData
并将其作为源删除:
val liveDataMerger: MediatorLiveData<Int> = MediatorLiveData()
val liveData = MutableLiveData<Int>()
val liveData2 = MutableLiveData<Int>()
liveDataMerger.addSource(liveData) { value ->liveDataMerger.setValue(value)}liveDataMerger.addSource(liveData2) { value2->var count = 1
count++
liveDataMerger.setValue(value2)
if (count > 5) {
liveDataMerger.removeSource(liveData2)
}}
If the given LiveData
is already added as a source but with a different Observer
, then IllegalArgumentException
will be thrown.
如果给定的 LiveData
已作为源添加,但具有不同的 Observer
,则将 IllegalArgumentException
。
转变 (Transformations)
The Transformations
class provides us with functions with which we can change the value in our LiveData object. Currently, we have 2 functions available in this class: map
and switchMap
.
Transformations
类为我们提供了一些函数,通过这些函数可以更改LiveData对象中的值。 当前,我们在此类中提供2个功能: map
和switchMap
。
map()
allows you to apply changes to each value as they’re emitted by LiveData
.This method is analogous to the Rx(io.reactivex.Observable)
map operator. The transform will be executed on the main
thread. Here is an example from the docs where a User
object is mapped to get the compete name:
map()
允许您将更改应用于LiveData
发出的每个值。 此方法类似于 Rx(io.reactivex.Observable)
映射运算符。 转换将在 main
线程 上执行 。 这是来自docs的示例,其中映射了User
对象以获取竞争名称:
LiveData<User> userLiveData = ...;LiveData<String> userFullNameLiveData =
Transformations.map(userLiveData,user ->
user.firstName + user.lastName);
});
As per documentation, the map
method code is as follows:
根据文档, map
方法代码如下:
@MainThread
public static <X, Y> LiveData<Y> map(
@NonNull LiveData<X> source,
@NonNull final Function<X, Y> mapFunction) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
result.addSource(source, new Observer<X>() {
@Override
public void onChanged(@Nullable X x) {
result.setValue(mapFunction.apply(x));
}
});
return result;
}
switchMap
returns a new LiveData
object rather than a value, i.e. it switches the actual LiveData
for a new one. This method is analogous to the Rx(io.reactivex.Observable)
switchMap operator. switchMapFunction
will be executed on the main
thread.
switchMap
返回一个新的LiveData
对象而不是一个值,即,它将实际的LiveData
切换为一个新的LiveData
对象。 此方法类似于 Rx(io.reactivex.Observable)
switchMap运算符。 switchMapFunction
将在 main
线程 上执行 。
Here is an example class that holds a typed-in name of a user which is String from an EditTex
in a MutableLiveData
and returns a LiveData
containing a list of user objects for users that have the same name. It populates that LiveData
by re-querying a repository-pattern object each time the typed name changes.
这里是保存的示例类一个键入的是字符串从一个用户的名称EditTex
在MutableLiveData
并返回一个LiveData
包含该具有相同的名称的用户的用户对象的列表。 每次键入的名称更改时,它LiveData
通过重新查询存储库模式对象来填充LiveData
。
class UserViewModel extends AndroidViewModel {
MutableLiveData<String> nameQueryLiveData = ...
LiveData<List<String>> getUsersWithNameLiveData() {
return Transformations.switchMap(
nameQueryLiveData,
name -> myDataSource.getUsersWithNameLiveData(name));
}
void setNameQuery(String name) {
this.nameQueryLiveData.setValue(name);
}
}
As per documentation, switchMap
method code is as follows:
根据文档, switchMap
方法代码如下:
Please give me your suggestions and comments.
请给我您的建议和意见。
Thanks for reading!
谢谢阅读!
翻译自: https://medium.com/better-programming/everything-to-should-understand-about-livedata-507dd83adea7
livedata