谷歌官方Android应用架构库——LiveData
2017-06-11 05:06
666 查看
架构库版本:1.0.0 Alpha 2 - June 2, 2017
LiveData 是一个数据持有者类,它持有一个值并允许观察该值。不同于普通的可观察者,LiveData 遵守应用程序组件的生命周期,以便 Observer 可以指定一个其应该遵守的 Lifecycle。
如果 Observer 的 Lifecycle 处于 STARTED 或 RESUMED 状态,LiveData 会认为 Observer 处于活动状态。
Location 监听的实现有 3 个重要部分:
onActive():当 LiveData 有一个处于活动状态的观察者时该方法被调用,这意味着需要开始从设备观察位置更新。
vonInactive():当 LiveData 没有任何处于活动状态的观察者时该方法被调用。由于没有观察者在监听,所以没有理由保持与 LocationManager 的连接。这是非常重要的,因为保持连接会显著消耗电量并且没有任何好处。
setValue():调用该方法更新 LiveData 实例的值,并将此变更通知给处于活动状态的观察者。
可以像下面这样使用新的 LocationLiveData:
请注意,addObserver() 方法将 LifecycleOwner 作为第一个参数传递。这样做表示该观察者应该绑定到 Lifecycle,意思是:
如果 Lifecycle 不处于活动状态(STARTED 或 RESUMED),即使该值发生变化也不会调用观察者。
如果 Lifecycle 被销毁,那么自动移除观察者。
LiveData 是生命周期感知的事实给我们提供了一个新的可能:可以在多个 activity,fragment 等之间共享它。为了保持实例简单,可以将其作为单例,如下所示:
现在 fragment 可以像下面这样使用它:
可能会有多个 fragment 和 activity 在观察 MyLocationListener 实例,LiveData 可以规范的管理它们,以便只有当它们中的任何一个可见(即处于活动状态)时才连接到系统服务。
LiveData 有以下优点:
没有内存泄漏:因为 Observer 被绑定到它们自己的 Lifecycle 对象上,所以,当它们的 Lifecycle 被销毁时,它们能自动的被清理。
不会因为 activity 停止而崩溃:如果 Observer 的 Lifecycle 处于闲置状态(例如:activity 在后台时),它们不会收到变更事件。
始终保持数据最新:如果 Lifecycle 重新启动(例如:activity 从后台返回到启动状态)将会收到最新的位置数据(除非还没有)。
正确处理配置更改:如果 activity 或 fragment 由于配置更改(如:设备旋转)重新创建,将会立即收到最新的有效位置数据。
资源共享:可以只保留一个 MyLocationListener 实例,只连接系统服务一次,并且能够正确的支持应用程序中的所有观察者。
不再手动管理生命周期:fragment 只是在需要的时候观察数据,不用担心被停止或者在停止之后启动观察。由于 fragment 在观察数据时提供了其 Lifecycle,所以 LiveData 会自动管理这一切。
Lifecycle 包提供了一个 Transformations 类包含对这些操作的帮助方法。
,%20android.arch.core.util.Function
,%20android.arch.core.util.Function
使用这些转换允许在整个调用链中携带观察者的 Lifecycle 信息,以便只有在观察者观察到 LiveData 的返回时才运算这些转换。转换的这种惰性运算性质允许隐式的传递生命周期相关行为,而不必添加显式的调用或依赖。
每当你认为在 ViewModel 中需要一个 Lifecycle 类时,转换可能是解决方案。
例如:假设有一个 UI,用户输入一个地址然后会收到该地址的邮政编码。该 UI 简单的 ViewModel 可能像这样:
如果是像这种实现,UI 需要先从之前的 LiveData 注销并且在每次调用 getPostalCode() 时重新注册到新的实例。此外,如果 UI 被重新创建,它将会触发新的 repository.getPostCode() 调用,而不是使用之前的调用结果。
不能使用那种方式,而应该实现将地址输入转换为邮政编码信息。
请注意,我们甚至使 postalCode 字段为 public final,因为它永远不会改变。postalCode 被定义为 addressInput 的转换,所以当 addressInput 改变时,如果有处于活动状态的观察者,repository.getPostCode() 将会被调用。如果在调用时没有处于活动状态的观察者,在添加观察者之前不会进行任何运算。
该机制允许以较少的资源根据需要惰性运算来创建 LiveData。ViewModel 可以轻松获取到 LiveData 并在它们上面定义转换规则。
LiveData 是一个数据持有者类,它持有一个值并允许观察该值。不同于普通的可观察者,LiveData 遵守应用程序组件的生命周期,以便 Observer 可以指定一个其应该遵守的 Lifecycle。
如果 Observer 的 Lifecycle 处于 STARTED 或 RESUMED 状态,LiveData 会认为 Observer 处于活动状态。
public class LocationLiveData extends LiveData<Location> { private LocationManager locationManager; private SimpleLocationListener listener = new SimpleLocationListener() { @Override public void onLocationChanged(Location location) { setValue(location); } }; public LocationLiveData(Context context) { locationManager = (LocationManager) context.getSystemService( Context.LOCATION_SERVICE); } @Override protected void onActive() { locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener); } @Override protected void onInactive() { locationManager.removeUpdates(listener); } }
Location 监听的实现有 3 个重要部分:
onActive():当 LiveData 有一个处于活动状态的观察者时该方法被调用,这意味着需要开始从设备观察位置更新。
vonInactive():当 LiveData 没有任何处于活动状态的观察者时该方法被调用。由于没有观察者在监听,所以没有理由保持与 LocationManager 的连接。这是非常重要的,因为保持连接会显著消耗电量并且没有任何好处。
setValue():调用该方法更新 LiveData 实例的值,并将此变更通知给处于活动状态的观察者。
可以像下面这样使用新的 LocationLiveData:
public class MyFragment extends LifecycleFragment { public void onActivityCreated (Bundle savedInstanceState) { LiveData<Location> myLocationListener = ...; Util.checkUserStatus(result -> { if (result) { myLocationListener.addObserver(this 4000 , location -> { // update UI }); } }); } }
请注意,addObserver() 方法将 LifecycleOwner 作为第一个参数传递。这样做表示该观察者应该绑定到 Lifecycle,意思是:
如果 Lifecycle 不处于活动状态(STARTED 或 RESUMED),即使该值发生变化也不会调用观察者。
如果 Lifecycle 被销毁,那么自动移除观察者。
LiveData 是生命周期感知的事实给我们提供了一个新的可能:可以在多个 activity,fragment 等之间共享它。为了保持实例简单,可以将其作为单例,如下所示:
public class LocationLiveData extends LiveData<Location> { private static LocationLiveData sInstance; private LocationManager locationManager; @MainThread public static LocationLiveData get(Context context) { if (sInstance == null) { sInstance = new LocationLiveData(context.getApplicationContext()); } return sInstance; } private SimpleLocationListener listener = new SimpleLocationListener() { @Override public void onLocationChanged(Location location) { setValue(location); } }; private LocationLiveData(Context context) { locationManager = (LocationManager) context.getSystemService( Context.LOCATION_SERVICE); } @Override protected void onActive() { locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener); } @Override protected void onInactive() { locationManager.removeUpdates(listener); } }
现在 fragment 可以像下面这样使用它:
public class MyFragment extends LifecycleFragment { public void onActivityCreated (Bundle savedInstanceState) { Util.checkUserStatus(result -> { if (result) { LocationLiveData.get(getActivity()).observe(this, location -> { // update UI }); } }); } }
可能会有多个 fragment 和 activity 在观察 MyLocationListener 实例,LiveData 可以规范的管理它们,以便只有当它们中的任何一个可见(即处于活动状态)时才连接到系统服务。
LiveData 有以下优点:
没有内存泄漏:因为 Observer 被绑定到它们自己的 Lifecycle 对象上,所以,当它们的 Lifecycle 被销毁时,它们能自动的被清理。
不会因为 activity 停止而崩溃:如果 Observer 的 Lifecycle 处于闲置状态(例如:activity 在后台时),它们不会收到变更事件。
始终保持数据最新:如果 Lifecycle 重新启动(例如:activity 从后台返回到启动状态)将会收到最新的位置数据(除非还没有)。
正确处理配置更改:如果 activity 或 fragment 由于配置更改(如:设备旋转)重新创建,将会立即收到最新的有效位置数据。
资源共享:可以只保留一个 MyLocationListener 实例,只连接系统服务一次,并且能够正确的支持应用程序中的所有观察者。
不再手动管理生命周期:fragment 只是在需要的时候观察数据,不用担心被停止或者在停止之后启动观察。由于 fragment 在观察数据时提供了其 Lifecycle,所以 LiveData 会自动管理这一切。
LiveData 的转换
有时候可能会需要在将 LiveData 发送到观察者之前改变它的值,或者需要更具另一个 LiveData 返回一个不同的 LiveData 实例。Lifecycle 包提供了一个 Transformations 类包含对这些操作的帮助方法。
,%20android.arch.core.util.Function
LiveData<User> userLiveData = ...; LiveData<String> userName = Transformations.map(userLiveData, user -> { user.name + " " + user.lastName });
,%20android.arch.core.util.Function
private LiveData<User> getUser(String id) { ...; } LiveData<String> userId = ...; LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );
使用这些转换允许在整个调用链中携带观察者的 Lifecycle 信息,以便只有在观察者观察到 LiveData 的返回时才运算这些转换。转换的这种惰性运算性质允许隐式的传递生命周期相关行为,而不必添加显式的调用或依赖。
每当你认为在 ViewModel 中需要一个 Lifecycle 类时,转换可能是解决方案。
例如:假设有一个 UI,用户输入一个地址然后会收到该地址的邮政编码。该 UI 简单的 ViewModel 可能像这样:
class MyViewModel extends ViewModel { private final PostalCodeRepository repository; public MyViewModel(PostalCodeRepository repository) { this.repository = repository; } private LiveData<String> getPostalCode(String address) { // DON'T DO THIS return repository.getPostCode(address); } }
如果是像这种实现,UI 需要先从之前的 LiveData 注销并且在每次调用 getPostalCode() 时重新注册到新的实例。此外,如果 UI 被重新创建,它将会触发新的 repository.getPostCode() 调用,而不是使用之前的调用结果。
不能使用那种方式,而应该实现将地址输入转换为邮政编码信息。
class MyViewModel extends ViewModel { private final PostalCodeRepository repository; private final MutableLiveData<String> addressInput = new MutableLiveData(); public final LiveData<String> postalCode = Transformations.switchMap(addressInput, (address) -> { return repository.getPostCode(address); }); public MyViewModel(PostalCodeRepository repository) { this.repository = repository } private void setInput(String address) { addressInput.setValue(address); } }
请注意,我们甚至使 postalCode 字段为 public final,因为它永远不会改变。postalCode 被定义为 addressInput 的转换,所以当 addressInput 改变时,如果有处于活动状态的观察者,repository.getPostCode() 将会被调用。如果在调用时没有处于活动状态的观察者,在添加观察者之前不会进行任何运算。
该机制允许以较少的资源根据需要惰性运算来创建 LiveData。ViewModel 可以轻松获取到 LiveData 并在它们上面定义转换规则。
创建新的转换
在应用程序中可能会用到十几种不同的特定转换,但是默认是不提供的。可以使用 MediatorLiveData 实现自己的转换,MediatorLiveData 是为了用来正确的监听其它 LiveData 实例并处理它们发出的事件而特别创建的。MediatorLiveData 需要特别注意正确的向源 LiveData 传递其处于活动/闲置状态。有关详细信息,请参阅 Transformations 类。相关文章推荐
- 谷歌官方Android应用架构库——ViewModel
- 谷歌官方Android应用架构库(Android Architecture Components)学习完整版
- 谷歌官方Android应用架构库——App 架构指南
- 谷歌官方Android应用架构库——ViewModel
- 谷歌官方Android应用架构库——处理生命周期
- 谷歌官方Android应用架构库——添加组件到项目中
- 谷歌官方Android应用架构库——Room 持久化库
- 谷歌官方推出Android应用开发架构组件介绍(Android Architecture Components)
- [置顶] 谷歌官方Android应用架构库——Room 持久化库
- Android 添加Google官方推出应用架构Architecture Components 的依赖
- Android应用之——谷歌官方Json解析工具Gson的使用
- Android中的应用——谷歌官方Json分析工具Gson使用
- Android开发之创建你的第一个应用(翻译自谷歌官方,原版翻译)
- 谷歌官方Android UI设计秘笈:第一部分
- 详解谷歌官方教程 Android插件ADT 9.0.0
- 谷歌计划远程关闭Android设备上恶意应用
- 详解谷歌官方教程 Android插件ADT 9.0.0
- Android设备上调用谷歌应用的的Intent 列表
- 索尼即将针对iPhone, Android发布官方应用
- 谷歌Android手机应用开发环境的搭建