PS:原文首发于微信公众号:躬行之(jzman-blog)

LiveData 是一个可观察的数据持有者类,与常规 observable 不同,LiveData 是生命周期感知的,LiveData 也是 Android Jetpack 组件的一部分,本文将从如下几个方面学习 LiveData:

  1. 什么是LiveData
  2. LiveData的优点
  3. LiveData的使用
  4. 自定义Livedata
  5. LiveData转换

什么是LiveData

LiveData 是一个可观察的数据持有者类,与常规的 Observable 不同,LiveData 可感知 Activity、Fragment、Service 的生命周期,确保 LiveData 仅更新处于活动生命周期状态的组件观察者。

如果应用程序组件观察者所处的状态是 STARTED 或 RESUMED,则 LiveData 认为该组件处于活跃状态,该组件会收到 LiveData 的数据更新,而其他注册的组件观察者将不会收到任何数据更新。

LiveData的优点

  • 保持UI与数据的一致性:LiveData 遵循观察者设计模式,生命周期发生变化时,LiveData 会通知对应的应用程序组件(Observer),数据发生变化时也会通知更新 UI.
  • 避免内存泄漏:这个 Observer 绑定了 Lifecycle 对象,当 Lifecycle 对象生命周期 destory 之后,这些 Observer 也会被自动清理。
  • 避免 Activity 处于不活跃状态的时候产生崩溃:如果观察者(Observer)处于不活跃状态,则 Observer 不会接收任何 LiveData 事件。
  • 不在手动处理生命周期:UI 组件只是观察相关数据,而不会停止或恢复观察,LiveData 会根据具体生命周期的变化而自动管理。
  • 始终保持最新数据:如果生命周期为非活跃状态,则会在由非活跃状态转为活跃状态时接收最新数据,如从后台切换到前台自动接收最新数据。
  • 正确处理配置更改:如果 Activity 或 Fragment 因为设备配置发生变化而重新创建,比如屏幕旋转等,也将会立即重新接收最新数据。
  • 共享服务:可以借助 LiveData 数据的观察能力,根据 Livecycle 的生命周期状态随时连接或断开服务。

LiveData的使用

在某个具体的 ViewModel 类中定义 LiveData 数据,然后在对应的 Activity 或 Fragment 中观察 LiveData 数据的变化,LiveData 的使用使得我们不在将数据保存在 Activity 或 Fragment 中,而是将 LiveData 对象中存储的数据保存在 ViewModel 中,减轻了 Activity 和 Fragment 的工作量,使得 Activity 和 Fragment 只负责界面管理和显示,而不在保存数据,且在配置更改时数据不受影响。

LiceData 使用方式总结:

  1. 在 ViewModel 创建具体的 LiveData 实例来存储数据,如下:
public class MViewModel extends ViewModel {    private MutableLiveData<String> data;    public LiveData<String> getData(){        if (data == null){            data = new MutableLiveData<>();            data.postValue(DataUtil.getData());        }        return data;    }}
  1. 使用 LiveData 对象的 observe 或 observeForever 方法将对应的 Activity 或 Fragment 等添加为该 LiveData 对象的观察者,如下:
@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    binding = DataBindingUtil.setContentView(this,R.layout.activity_main);    MViewModel mViewModel = ViewModelProviders.of(this).get(MViewModel.class);    mViewModel.getData().observe(this, new Observer<String>() {        @Override        public void onChanged(String msg) {            binding.setData(msg);        }    });}
  1. 使用 LiveData 的 setValue 或 postValue 更新数据,然后在观察者,也就是 Activity 或 Fragment 中就获取更新数据了,如下:
public void setData(String data) {    mData.setValue(data);}

那么如何创建没有 LifecycleOwner 的观察者呢? 可以使用 LiveData 对象的 observeForever 方法来将一个没有 LifecycleOwner 的类添加到观察者列表中,如下:

public class NoLifecycleOwner {    public void print(NViewModel viewModel, final TextView tvData){        //使用observeForever对象创建没有LifecycleOwner的观察者        viewModel.getData().observeForever(new Observer<String>() {            @Override            public void onChanged(String s) {                tvData.setText("我是没有LifecycleOwner的观察者:"+s);            }        });    }}

不过使用 observeForever 获得观察者对象会一直处于活跃状态,此时就需要我们手动调用 removeObserver(Observer) 移除该观察者。

自定义Livedata

可以使用 LiveData 对象具有生命周期感知能力对外提供服务,可以很方便的控制服务的开启和关闭,如下:

/** * 自定义LiveData * Powered by jzman. * Created on 2018/12/17 0017. */public class CustomLiveData extends LiveData<String> {    @Override    protected void onActive() {        //有活跃观察者调用该方法        //开启服务...    }    @Override    protected void onInactive() {        //没有任何活跃观察者调用该方法        //结束服务...    }}

LiveData转换

Lifecycle 提供了工具类 Transformations 来对 LiveData 的数据类型进行转换,可以在 LiveData 在数据返回给观察者之前修改 LiveData 中数据的具体类型,比如 int 型数字 1、2 等转化为中文大写壹、贰等,那么如何使用呢,创建 MapViewModel 如下:

/** * LiveData转换 * Powered by jzman. * Created on 2018/12/17 0017. */public class MapViewModel extends ViewModel {    private MutableLiveData<Integer> mPrice = new MutableLiveData<>();    //Map    private LiveData<String> mMapPrice = Transformations.map(mPrice, new Function<Integer, String>() {        @Override        public String apply(Integer input) {            //返回String            return Util.getNumberCapital(input);        }    });    //SwitchMap    private LiveData<String> mSwitchMapPrice = Transformations.switchMap(mPrice, new Function<Integer, LiveData<String>>() {        @Override        public LiveData<String> apply(Integer input) {            //返回LiveData            MutableLiveData<String> data = new MutableLiveData<>();            data.postValue(Util.getNumberCapital(input));            return data;        }    });    public void setPrice(int price) {        mPrice.setValue(price);    }    public LiveData<String> getPrice() {        //Map        return mMapPrice;        //SwitchMap//        return mSwitchMapPrice;    }}

然后,在 Activity 观察数据的变化即可,如下:

public class MapActivity extends AppCompatActivity {    private MapViewModel mapViewModel;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        final ActivityMapBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_map);        mapViewModel = new MapViewModel();        mapViewModel.getPrice().observe(this, new Observer<String>() {            @Override            public void onChanged(String s) {                //数字转换为中文大写                binding.tvData.setText(s);            }        });    }    public void btnSetPrice1(View view) {        mapViewModel.setPrice(1);    }    public void btnSetPrice2(View view) {        mapViewModel.setPrice(2);    }}

Transformations 工具类中 map 和 switchMap 方法唯一的区别是 map 将 LiveData 数据转换为具体的类型,如上述代码中的 String,而 switchMap 则是 LiveData,上述代码中 getNumberCapital 方法只是大小写转化的一个方法就不贴了,测试效果如下:

map 方法和 switchMap 方法内部都是由 MediatorLiveData 参与转换,可以自己使用 MediatorLiveData 来实现更多类似 map 、 switch 这样的数据类型转换。

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. 一句话锁定MySQL数据占用元凶
  3. GreenDao 问题集合
  4. Android(安卓)音视频开发(五) -- 使用 MediaExtractor 分离音视
  5. Android中Activity组件的生命周期
  6. Android(安卓)- Fragment(碎片) 详解
  7. MVVM实现数据双向绑定
  8. Android中保存和恢复Fragment状态的最好方法
  9. java读取文本文件内容2

随机推荐

  1. Android动态加载jar、apk的实现
  2. Android之——获取进程总数、内存、任务
  3. Android开机自动运行服务
  4. 在 Ubuntu 10.04 下面安装 Android USB
  5. 以一个小程序设计来入门Android
  6. Android之Fragment学习(二)
  7. Android软硬整合技术(HAL&Framework)
  8. Android Project和app中两个build.gradle
  9. 关于Android SDK 文档的一点小错误 Galle
  10. Android中的Adapter 详解(三)