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

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

[[197255]]

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); 
    } 
 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.

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, location -> { 
                    // update UI 
                }); 
            } 
        }); 
    } 
 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

请注意,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); 
    } 
 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.

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

public class MyFragment extends LifecycleFragment { 
    public void onActivityCreated (Bundle savedInstanceState) { 
        Util.checkUserStatus(result -> { 
            if (result) { 
                LocationLiveData.get(getActivity()).observe(this, location -> { 
                   // update UI 
                }); 
            } 
        }); 
  } 
 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 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

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

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

private LiveData<User> getUser(String id) { 
  ...; 

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

使用这些转换允许在整个调用链中携带观察者的 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); 
    } 
 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

如果是像这种实现,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); 
  } 
 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

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

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

创建新的转换

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

责任编辑:庞桂玉 来源: Android开发中文站
相关推荐

2019-10-11 09:38:56

谷歌Android开发者

2017-05-25 12:30:44

AndroidApp开发架构

2011-02-17 13:35:12

ADT 9.0.0ADT下载ADT安装

2012-04-25 22:58:36

2011-03-17 08:58:09

数据储存Data StoragAndroid API

2011-09-05 14:02:53

Android视频教程

2010-02-06 15:32:30

Android架构

2017-06-30 09:36:10

Android OAPI兼容

2025-02-28 16:58:00

2010-02-06 15:53:55

2022-03-04 15:44:45

MVI 架构LiveData代码

2011-03-07 09:33:37

2011-02-18 14:02:36

Android R5 Android NDKAndroid NDK

2017-11-28 11:19:55

SDN架构驱动

2021-09-07 06:40:25

AndroidLiveData原理

2010-02-06 15:26:11

Android应用程序

2012-02-03 09:14:44

谷歌恶意应用Android

2011-03-31 09:16:39

Android Mar付费

2011-10-25 09:58:39

谷歌Android Mar

2011-07-22 13:32:33

Android Mar谷歌应用商店
点赞
收藏

51CTO技术栈公众号