LiveData 是一个数据持有者类,它持有一个值并容许观察该值。不一样于普通的可观察者,LiveData 遵照应用程序组件的生命周期,以便 Observer 能够指定一个其应该遵照的 Lifecycle。javascript
注:在 Android 项目中导入 LiveData,请参阅添加组件到项目中html
若是 Observer 的 Lifecycle 处于 STARTED 或 RESUMED 状态,LiveData 会认为 Observer 处于活动状态。java
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 个重要部分:android
onActive()git
当 LiveData 有一个处于活动状态的观察者时该方法被调用,这意味着须要开始从设备观察位置更新。github
onInactive()app
当 LiveData 没有任何处于活动状态的观察者时该方法被调用。因为没有观察者在监听,因此没有理由保持与 LocationManager 的链接。这是很是重要的,由于保持链接会显著消耗电量而且没有任何好处。ide
setValue()post
调用该方法更新 LiveData 实例的值,并将此变动通知给处于活动状态的观察者。ui
能够像下面这样使用新的 LocationLiveData:
public class MyFragment extends LifecycleFragment {
public void onActivityCreated (Bundle savedInstanceState) {
LiveData<Location> myLocationListener = ...;
Util.checkUserStatus(result -> {
if (result) {
myLocationListener.addObserver(this, location -> {
// 更新 UI
});
}
});
}
}复制代码
请注意,addObserver() 方法将 LifecycleOwner 做为第一个参数传递。这样作表示该观察者应该绑定到 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 实例。
Lifecycle 包提供了一个 Transformations 类包含对这些操做的帮助方法。
在 LiveData 的值上应用一个方法,并将结果传递到下游。
LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
user.name + " " + user.lastName
});复制代码
与 map() 相似,将一个方法应用到 LiveData 的值并解包,而后将结果传递到下游。传递给 switchMap() 的方法必须返回一个 Lifecycle
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) {
// 不要这样作!!!
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 类。