谷歌官方Android应用架构库——LiveData

简介:

谷歌官方Android应用架构库——LiveData

LiveData 是一个数据持有者类,它持有一个值并允许观察该值。不同于普通的可观察者,LiveData 遵守应用程序组件的生命周期,以便 Observer 可以指定一个其应该遵守的 Lifecycle。

如果 Observer 的 Lifecycle 处于 STARTED 或 RESUMED 状态,LiveData 会认为 Observer 处于活动状态。


  
  
  1. public class LocationLiveData extends LiveData<Location> { 
  2.     private LocationManager locationManager; 
  3.  
  4.     private SimpleLocationListener listener = new SimpleLocationListener() { 
  5.         @Override 
  6.         public void onLocationChanged(Location location) { 
  7.             setValue(location); 
  8.         } 
  9.     }; 
  10.  
  11.     public LocationLiveData(Context context) { 
  12.         locationManager = (LocationManager) context.getSystemService( 
  13.                 Context.LOCATION_SERVICE); 
  14.     } 
  15.  
  16.     @Override 
  17.     protected void onActive() { 
  18.         locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener); 
  19.     } 
  20.  
  21.     @Override 
  22.     protected void onInactive() { 
  23.         locationManager.removeUpdates(listener); 
  24.     } 
  25.  

Location 监听的实现有 3 个重要部分:

  • onActive():当 LiveData 有一个处于活动状态的观察者时该方法被调用,这意味着需要开始从设备观察位置更新。
  • vonInactive():当 LiveData 没有任何处于活动状态的观察者时该方法被调用。由于没有观察者在监听,所以没有理由保持与 LocationManager 的连接。这是非常重要的,因为保持连接会显著消耗电量并且没有任何好处。
  • setValue():调用该方法更新 LiveData 实例的值,并将此变更通知给处于活动状态的观察者。

可以像下面这样使用新的 LocationLiveData:


  
  
  1. public class MyFragment extends LifecycleFragment { 
  2.     public void onActivityCreated (Bundle savedInstanceState) { 
  3.         LiveData<Location> myLocationListener = ...; 
  4.         Util.checkUserStatus(result -> { 
  5.             if (result) { 
  6.                 myLocationListener.addObserver(this, location -> { 
  7.                     // update UI 
  8.                 }); 
  9.             } 
  10.         }); 
  11.     } 
  12.  

请注意,addObserver() 方法将 LifecycleOwner 作为第一个参数传递。这样做表示该观察者应该绑定到 Lifecycle,意思是:

  • 如果 Lifecycle 不处于活动状态(STARTED 或 RESUMED),即使该值发生变化也不会调用观察者。
  • 如果 Lifecycle 被销毁,那么自动移除观察者。

LiveData 是生命周期感知的事实给我们提供了一个新的可能:可以在多个 activity,fragment 等之间共享它。为了保持实例简单,可以将其作为单例,如下所示:


  
  
  1. public class LocationLiveData extends LiveData<Location> { 
  2.     private static LocationLiveData sInstance; 
  3.     private LocationManager locationManager; 
  4.  
  5.     @MainThread 
  6.     public static LocationLiveData get(Context context) { 
  7.         if (sInstance == null) { 
  8.             sInstance = new LocationLiveData(context.getApplicationContext()); 
  9.         } 
  10.         return sInstance; 
  11.     } 
  12.  
  13.     private SimpleLocationListener listener = new SimpleLocationListener() { 
  14.         @Override 
  15.         public void onLocationChanged(Location location) { 
  16.             setValue(location); 
  17.         } 
  18.     }; 
  19.  
  20.     private LocationLiveData(Context context) { 
  21.         locationManager = (LocationManager) context.getSystemService( 
  22.                 Context.LOCATION_SERVICE); 
  23.     } 
  24.  
  25.     @Override 
  26.     protected void onActive() { 
  27.         locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener); 
  28.     } 
  29.  
  30.     @Override 
  31.     protected void onInactive() { 
  32.         locationManager.removeUpdates(listener); 
  33.     } 
  34.  

现在 fragment 可以像下面这样使用它:


  
  
  1. public class MyFragment extends LifecycleFragment { 
  2.     public void onActivityCreated (Bundle savedInstanceState) { 
  3.         Util.checkUserStatus(result -> { 
  4.             if (result) { 
  5.                 LocationLiveData.get(getActivity()).observe(this, location -> { 
  6.                    // update UI 
  7.                 }); 
  8.             } 
  9.         }); 
  10.   } 
  11.  

可能会有多个 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


  
  
  1. LiveData<User> userLiveData = ...; 
  2. LiveData<String> userName = Transformations.map(userLiveData, user -> { 
  3.     user.name + " " + user.lastName 
  4. });  

,%20android.arch.core.util.Function


  
  
  1. private LiveData<User> getUser(String id) { 
  2.   ...; 
  3.  
  4. LiveData<String> userId = ...; 
  5. LiveData<Useruser = Transformations.switchMap(userId, id -> getUser(id) );  

使用这些转换允许在整个调用链中携带观察者的 Lifecycle 信息,以便只有在观察者观察到 LiveData 的返回时才运算这些转换。转换的这种惰性运算性质允许隐式的传递生命周期相关行为,而不必添加显式的调用或依赖。

每当你认为在 ViewModel 中需要一个 Lifecycle 类时,转换可能是解决方案。

例如:假设有一个 UI,用户输入一个地址然后会收到该地址的邮政编码。该 UI 简单的 ViewModel 可能像这样:


  
  
  1. class MyViewModel extends ViewModel { 
  2.     private final PostalCodeRepository repository; 
  3.     public MyViewModel(PostalCodeRepository repository) { 
  4.        this.repository = repository; 
  5.     } 
  6.  
  7.     private LiveData<String> getPostalCode(String address) { 
  8.        // DON'T DO THIS 
  9.        return repository.getPostCode(address); 
  10.     } 
  11.  

如果是像这种实现,UI 需要先从之前的 LiveData 注销并且在每次调用 getPostalCode() 时重新注册到新的实例。此外,如果 UI 被重新创建,它将会触发新的 repository.getPostCode() 调用,而不是使用之前的调用结果。

不能使用那种方式,而应该实现将地址输入转换为邮政编码信息。


  
  
  1. class MyViewModel extends ViewModel { 
  2.     private final PostalCodeRepository repository; 
  3.     private final MutableLiveData<String> addressInput = new MutableLiveData(); 
  4.     public final LiveData<String> postalCode = 
  5.             Transformations.switchMap(addressInput, (address) -> { 
  6.                 return repository.getPostCode(address); 
  7.              }); 
  8.  
  9.   public MyViewModel(PostalCodeRepository repository) { 
  10.       this.repository = repository 
  11.   } 
  12.  
  13.   private void setInput(String address) { 
  14.       addressInput.setValue(address); 
  15.   } 
  16.  

请注意,我们甚至使 postalCode 字段为 public final,因为它永远不会改变。postalCode 被定义为 addressInput 的转换,所以当 addressInput 改变时,如果有处于活动状态的观察者,repository.getPostCode() 将会被调用。如果在调用时没有处于活动状态的观察者,在添加观察者之前不会进行任何运算。

该机制允许以较少的资源根据需要惰性运算来创建 LiveData。ViewModel 可以轻松获取到 LiveData 并在它们上面定义转换规则。

创建新的转换

在应用程序中可能会用到十几种不同的特定转换,但是默认是不提供的。可以使用 MediatorLiveData 实现自己的转换,MediatorLiveData 是为了用来正确的监听其它 LiveData 实例并处理它们发出的事件而特别创建的。MediatorLiveData 需要特别注意正确的向源 LiveData 传递其处于活动/闲置状态。有关详细信息,请参阅 Transformations 类。






本文作者:佚名
来源:51CTO
目录
相关文章
|
2月前
|
运维 Cloud Native 持续交付
深入理解云原生架构及其在现代企业中的应用
随着数字化转型的浪潮席卷全球,企业正面临着前所未有的挑战与机遇。云计算技术的迅猛发展,特别是云原生架构的兴起,正在重塑企业的IT基础设施和软件开发模式。本文将深入探讨云原生的核心概念、关键技术以及如何在企业中实施云原生策略,以实现更高效的资源利用和更快的市场响应速度。通过分析云原生架构的优势和面临的挑战,我们将揭示它如何助力企业在激烈的市场竞争中保持领先地位。
|
19天前
|
机器学习/深度学习 人工智能 并行计算
Titans:谷歌新型神经记忆架构,突破 Transformer 长序列处理的瓶颈
Titans 是谷歌推出的新型神经网络架构,通过神经长期记忆模块突破 Transformer 在处理长序列数据时的瓶颈,支持并行计算,显著提升训练效率。
78 5
Titans:谷歌新型神经记忆架构,突破 Transformer 长序列处理的瓶颈
|
1月前
|
容灾 网络协议 数据库
云卓越架构:云上网络稳定性建设和应用稳定性治理最佳实践
本文介绍了云上网络稳定性体系建设的关键内容,包括面向失败的架构设计、可观测性与应急恢复、客户案例及阿里巴巴的核心电商架构演进。首先强调了网络稳定性的挑战及其应对策略,如责任共担模型和冗余设计。接着详细探讨了多可用区部署、弹性架构规划及跨地域容灾设计的最佳实践,特别是阿里云的产品和技术如何助力实现高可用性和快速故障恢复。最后通过具体案例展示了秒级故障转移的效果,以及同城多活架构下的实际应用。这些措施共同确保了业务在面对网络故障时的持续稳定运行。
|
3月前
|
Cloud Native 安全 持续交付
深入理解微服务架构及其在现代软件开发中的应用
深入理解微服务架构及其在现代软件开发中的应用
109 32
|
2月前
|
网络协议 Linux Android开发
深入探索Android系统架构与性能优化
本文旨在为读者提供一个全面的视角,以理解Android系统的架构及其关键组件。我们将探讨Android的发展历程、核心特性以及如何通过有效的策略来提升应用的性能和用户体验。本文不包含常规的技术细节,而是聚焦于系统架构层面的深入分析,以及针对开发者的实际优化建议。
107 21
|
2月前
|
存储 Linux API
深入探索Android系统架构:从内核到应用层的全面解析
本文旨在为读者提供一份详尽的Android系统架构分析,从底层的Linux内核到顶层的应用程序框架。我们将探讨Android系统的模块化设计、各层之间的交互机制以及它们如何共同协作以支持丰富多样的应用生态。通过本篇文章,开发者和爱好者可以更深入理解Android平台的工作原理,从而优化开发流程和提升应用性能。
|
2月前
|
安全 Android开发 iOS开发
深入探索iOS与Android系统架构差异及其对开发者的影响
本文旨在通过对比分析iOS和Android两大移动操作系统的系统架构,探讨它们在设计理念、技术实现及开发者生态方面的差异。不同于常规摘要仅概述内容要点,本摘要将简要触及核心议题,为读者提供对两大平台架构特点的宏观理解,铺垫
|
3月前
|
运维 Kubernetes Docker
深入理解容器化技术及其在微服务架构中的应用
深入理解容器化技术及其在微服务架构中的应用
96 1
|
2月前
|
开发工具 Android开发 iOS开发
Android与iOS生态差异深度剖析:技术架构、开发体验与市场影响####
本文旨在深入探讨Android与iOS两大移动操作系统在技术架构、开发环境及市场表现上的核心差异,为开发者和技术爱好者提供全面的视角。通过对比分析,揭示两者如何塑造了当今多样化的移动应用生态,并对未来发展趋势进行了展望。 ####
|
2月前
|
弹性计算 API 持续交付
后端服务架构的微服务化转型
本文旨在探讨后端服务从单体架构向微服务架构转型的过程,分析微服务架构的优势和面临的挑战。文章首先介绍单体架构的局限性,然后详细阐述微服务架构的核心概念及其在现代软件开发中的应用。通过对比两种架构,指出微服务化转型的必要性和实施策略。最后,讨论了微服务架构实施过程中可能遇到的问题及解决方案。