简介:
LiveData 数据观察者持有类 拥有生命周期感应的特性 所以他实在对应组件的生命周期内(例如 activity fragment service 等等)完成数据活动
liveDate 也可以理解成一个观察者 在被观察者(生命活动持有者)的生命周期处在onstart 或者onResume 的状态下 也就是active的状态下 可以接受到liveData的事件通知 再非active 的状态下 将无法接收到liveData的任何事件 那么这样就可以完全避免内存泄漏的风险了
那么下面的问题就是liveData怎么知道被观察者的生命状态呢 我们这里就要结合上篇文章中的lifecycle-aware来实现 不知道的小伙伴可以去翻下 这里就不给链接了 再上一篇中我们知道 只要你实现的lifecycleOwener 接口 那么就可以注册生命周期观察者 来感知被观察者生命周期的变化了 (PS: 对于activity和fragment 系统已经帮我们实现了lifecycleowner接口 ) 下面就简单了 我们只需要把我们的liveData 当做观察者注册到生命活动持有者(activity、fragment中就可以了 ) 是不是很简单 看不懂没关系 继续往下走就好了
我们先看下liveData的优点:
使用LiveData提供以下优点:
保证用户界面与数据状态匹配
LiveData遵循观察者模式。在生命周期状态更改时LiveData会通知Observer对象。您可以升级代码在observer
对象中更新UI,不必每次数据改变时手动更新UI,观察者可以在每次更改时更新UI。没有内存泄漏
观察者与Lifecycle对象绑定,并在具有生命周期的对象被destroyed
后自行清理。停止
activities
不会导致崩溃
如果观察者的生命周期处于非活动状态,例如在后退堆栈中的活动,则不会收到任何LiveData事件。无需手动处理生命周期
UI组件只是观察相关数据,不会停止或恢复观察。LiveData自动管理所有这些操作,因为在观察时它实时响应相关的生命周期状态的变化。始终保持最新的数据
如果生命周期变为非活动状态,它将在再次变为活动状态时接收到最新的数据。例如,后台活动在返回到前台后立即收到最新数据。正确的配置更改
如果由于配置更改(如设备旋转)而重新创建活动或片段,则会立即收到最新的可用数据。共享资源
可以使用单例模式来扩展LiveData对象来包装系统服务,以便它们可以在应用程序中共享。LiveData
对象一旦连接到系统服务,然后其他任何需要系统资源的观察者只需要观看该LiveData
对象就可以。
看到这里是不是有些激动了 那我们写几个demo看下 是不是真的这么好用 :
我们看下liveData的用法:
1.在project build.gradle中添加google()仓库引用
repositories { google() jcenter() }
2. 在app build.gradle中添加插件引用
// ViewModel and LiveData implementation "android.arch.lifecycle:extensions:1.1.1" // alternatively, just ViewModel implementation "android.arch.lifecycle:viewmodel:1.1.1" // alternatively, just LiveData implementation "android.arch.lifecycle:livedata:1.1.1"
3.下面我们开始码代码
PS:一般liveData 对象一般存储在VIewModel中 关于ViewModel 我们下一章中会具体介绍
那么首先我们先创建 ViewModel 来保存 LiveData对象
public class MyViewModel extends ViewModel { /** * liveData 对象MutableLiveData 是LiveData(抽象类)的子类 */ private MutableLiveData<String> mutableLiveData; public MutableLiveData<String> getCurrentName() { if (mutableLiveData == null) { mutableLiveData = new MutableLiveData<>(); } return mutableLiveData; } }
PS:这里我们使用了系统提供的MutableLiveData 创建liveData实例 这里我要说下 所谓liveData对象 只需要继承LiveData的类创建出来的都是LiveData 再后面我们会自己定义LiveData对象 这里不多说
创建了LiveData对象 并存储在ViewModel中 之后我们需要一个被观察者(生命周期持有者) 这里我们使用Activity当demo
创建ViewModel 对象 然后将注册生命周期持有者 这样我们就将 生命周期持有者 和liveData 关联起来了
我们再onResume中 模拟了 数据变化的过程 具体运行结果 看你喽 如果还是不懂没关系 继续
public class MainActivity extends AppCompatActivity { private static final String TAG = "lifeCycle"; private MyViewModel myViewModel; private int count = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 获取ModelView对象 myViewModel = ViewModelProviders.of(this).get(MyViewModel.class); addLiveDataObject(); } /** * 添加liveData观察对象 * 一般放在oncreate中执行 为了防止反复执行 */ private void addLiveDataObject() { // 注册观察者(生命周期活动持有者 在这里就是我们的activity) 观察行为(当接收到livedata通知之后的相应行为) // 完成之后 我们再onResume中更新下数据 myViewModel.getCurrentName().observe(this, observer); } Observer<String> observer = new Observer<String>() { @Override public void onChanged(@Nullable String s) { // livedata 通知之后的行为 这里可以进行UI更新 比如 textView.setText(s)啥的 不做了 Log.d(TAG, "onChanged=" + s); } }; @Override protected void onResume() { super.onResume(); count++; myViewModel.getCurrentName().setValue("dataChangeCount=" + count); Log.d(TAG, "onResume"); } @Override protected void onStart() { super.onStart(); Log.d(TAG, "onStart"); } @Override protected void onPause() { super.onPause(); Log.d(TAG, "onPause"); } @Override protected void onStop() { super.onStop(); Log.d(TAG, "onStop"); } }
上面的用法 我们都看了一下 关于用法有了大概了解 但是 很懵懂吧 那么下面我们自己定义一个liveData 估计你就很清楚了
1.创建股价波动类模拟真实数据获取
public interface SimplePriceChangeListener { void onChange(int price); }
public class StockManager { public void requestPriceUpdate(final SimplePriceChangeListener mListener) { new Thread(new Runnable() { @Override public void run() { // 模拟股市波动 1股每1s 涨1块钱 高兴 for (int i = 0; i < 50; i++) { SystemClock.sleep(1000); if (mListener != null) { mListener.onChange(i + 100); } } } }).start(); } public void removeListener(SimplePriceChangeListener mListener) { // 随意写 mListener = null; } }当请求估计的时候 我们模拟网络请求返回 这里再看不懂 借你我的长发
2.自定义liveData(这次我们不在使用系统现有的 )
刚刚我们说过 需要继承LiveData 那么就不得不说liveData的两个方法
onActive onInactive 我们上面已经说过 当被观察者处在active状态的时候可以接受liveData的通知 处在inActive 的状态下 接受不到 那么我们这里的onActive onInactive两个方法 大家应该知道是什么鬼了吧 就是对应被观察者的生命周期状态 一般我们再active中完成数据的实时更新 再Inactive中完成监听的移除等等操作(就像onDestory的用处一样)
废话少说 上代码
public class StockLiveData extends LiveData<Integer> { private StockManager mStokeManager; private SimplePriceChangeListener mListener = new SimplePriceChangeListener() { @Override public void onChange(int price) { // 因为onchange我们再子线程里面调用的 这里我们不适用 setValue postValue(price); } }; public StockLiveData() { this.mStokeManager = new StockManager(); } @Override protected void onActive() { super.onActive(); mStokeManager.requestPriceUpdate(mListener); } @Override protected void onInactive() { super.onInactive(); mStokeManager.removeListener(mListener); } }
这里我们出现了postValue()方法 上面我们模拟值得时候用的setValue 这里说下两个方法 都是用来发送值变化事件的 但是 如果你当前线程是主线程 那么就使用setValue 如果是子线程 那么就用postValue 像不像Handler 哈哈~我自己瞎想的
那么下面我们像上面一样 将liveData添加到ViewModel中
public class MyViewModel extends ViewModel { /** * liveData 对象MutableLiveData 是LiveData(抽象类)的子类 */ private MutableLiveData<String> mutableLiveData; private StockLiveData mStockLiveData; public MutableLiveData<String> getCurrentName() { if (mutableLiveData == null) { mutableLiveData = new MutableLiveData<>(); } return mutableLiveData; } public StockLiveData getCustomLiveDataName() { if (mStockLiveData == null) { mStockLiveData = new StockLiveData(); } return mStockLiveData; } }
这里 大概大家就能大概明白一样 VIewModel 岁LiveData进行统一管理了吧
下一步 和被观察者关联
public class MainActivity extends AppCompatActivity { private static final String TAG = "lifeCycle"; private MyViewModel myViewModel; private int count = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // addLifeCycleObserve(); // 获取ModelView对象 myViewModel = ViewModelProviders.of(this).get(MyViewModel.class); // addLiveDataObject(); // 按照之前的步骤 搞定 addCustomLiveDataObject(); } private void addCustomLiveDataObject() { myViewModel.getCustomLiveDataName().observe(this, customObserver); } Observer<Integer> customObserver = new Observer<Integer>() { @Override public void onChanged(@Nullable Integer integer) { Log.d(TAG, "current price=" + integer); } }; /** * 添加liveData观察对象 * 一般放在oncreate中执行 为了防止反复执行 */ private void addLiveDataObject() { // 注册观察者(生命周期活动持有者 在这里就是我们的activity) 观察行为(当接收到livedata通知之后的相应行为) // 完成之后 我们再onResume中更新下数据 myViewModel.getCurrentName().observe(this, observer); } Observer<String> observer = new Observer<String>() { @Override public void onChanged(@Nullable String s) { // livedata 通知之后的行为 这里可以进行UI更新 比如 textView.setText(s)啥的 不做了 Log.d(TAG, "onChanged=" + s); } }; @Override protected void onResume() { super.onResume(); count++; myViewModel.getCurrentName().setValue("dataChangeCount=" + count); Log.d(TAG, "onResume"); } @Override protected void onStart() { super.onStart(); Log.d(TAG, "onStart"); } @Override protected void onPause() { super.onPause(); Log.d(TAG, "onPause"); } @Override protected void onStop() { super.onStop(); Log.d(TAG, "onStop"); } /** * 注册生命周期观察者 */ private void addLifeCycleObserve() { MyObserver myObserver = new MyObserver(); getLifecycle().addObserver(myObserver); } }
为了做对比我放在了 刚刚的mainActivity中了 和刚刚步骤一样只是这次获取的是自定义LiveData对象 那么我们跑下
03-26 16:12:02.485 27899-27899/com.example.lifeapplication D/lifeCycle: current price=100
03-26 16:12:03.486 27899-27899/com.example.lifeapplication D/lifeCycle: current price=101
03-26 16:12:04.487 27899-27899/com.example.lifeapplication D/lifeCycle: current price=102
03-26 16:12:04.959 27899-27899/com.example.lifeapplication D/lifeCycle: onPause
03-26 16:12:04.982 27899-27899/com.example.lifeapplication D/lifeCycle: onStop
03-26 16:12:07.068 27899-27899/com.example.lifeapplication D/lifeCycle: onStart
03-26 16:12:07.069 27899-27899/com.example.lifeapplication D/lifeCycle: current price=104
03-26 16:12:07.070 27899-27899/com.example.lifeapplication D/lifeCycle: onResume
03-26 16:12:07.487 27899-27899/com.example.lifeapplication D/lifeCycle: current price=105
03-26 16:12:08.070 27899-27899/com.example.lifeapplication D/lifeCycle: current price=100
03-26 16:12:08.488 27899-27899/com.example.lifeapplication D/lifeCycle: current price=106
03-26 16:12:08.534 27899-27899/com.example.lifeapplication D/lifeCycle: onPause
03-26 16:12:08.552 27899-27899/com.example.lifeapplication D/lifeCycle: onStop
03-26 16:12:13.475 27899-27899/com.example.lifeapplication D/lifeCycle: onStart
03-26 16:12:13.476 27899-27899/com.example.lifeapplication D/lifeCycle: current price=105
大家发现了吧 当生命活动是inactive的时候 没有接收到数据变化 但是数据仍然在更新 当active的时候 能够立即获取到数据 怎么样 方便吗? 大概 懂一点了 那我们继续
关于liveData 转换
很多时候我们会用到 请求到的是一个实体类 我们需要的是String 串 关于liveData 系统给我们提供了转换规则
这里我就直接简写了
public class MyViewModel extends ViewModel { /** * liveData 对象MutableLiveData 是LiveData(抽象类)的子类 */ private MutableLiveData<String> mutableLiveData; private StockLiveData mStockLiveData; public MutableLiveData<String> getCurrentName() { if (mutableLiveData == null) { mutableLiveData = new MutableLiveData<>(); } return mutableLiveData; } public StockLiveData getCustomLiveDataName() { if (mStockLiveData == null) { mStockLiveData = new StockLiveData(); } return mStockLiveData; } public LiveData<String> getStringLiveData() { return Transformations.map(mStockLiveData, String::valueOf); } }
具体使用方式和之前的是一样的
类似于Map()
,对存储在LiveData对象中的值应用一个函数,打开并分派结果数据流。传递给switchMap()的方法必须返回一个
关于这个方法的官方说法 我没有看懂 随便写个demo 实现 暂时放着 接下来 我们看下 这个方法的实际意义
public LiveData<User> getSwitchLiveData() { MutableLiveData<String> userMutableLiveData = new MutableLiveData<>(); userMutableLiveData.setValue("Tom"); return Transformations.switchMap(userMutableLiveData, name -> getUser(name)); } private LiveData<User> getUser(String name) { MutableLiveData<User> userMutableLiveData = new MutableLiveData<>(); userMutableLiveData.setValue(new User(name, 18)); return null; }
PS:这种转化 是惰性的 如果当前生命周期持有者 处于active状态 需要获取当前数据 那么才会进行转换
我们先写一个 demo
如果我们有一个获取地址返回邮政编码的组件 我们很有可能这样写
public LiveData<String> getPostalCodeLiveData(String addressName) { return PostalCodeResp.getPostalCode(addressName); }
public static LiveData<String> getPostalCode(String addressName) { String postalCode = "邮政编码:" + addressName; return new LiveData<String>() { @Override protected void onActive() { super.onActive(); setValue(postalCode); } }; }
如果是这样的话 当UI组件销毁重建的时候 我们就会触发 getPostalCode方法 而不是使用先前调用的结果 但是我们的邮政编码是finial的 如果地址一样我们只需要返回之前 回调结果 只有当地址发生变化的时候 我们才需要去调用获取方法 所以 我们队这段代码进行优化
private PostalCodeResp repository; private final MutableLiveData<String> addressInput = new MutableLiveData(); public final LiveData<String> postalCode = Transformations.switchMap(addressInput, (address) -> repository.getPostalCode(address)); private void setInput(String address) { addressInput.setValue(address); }
这样的话 只有setInput 被调用重置地址的时候 我们的getPostalCode 方法 才会调用 这样是不是省了一点开销
关于转换规则 我们就整到这 创建新的转化规则以及合并liveData源 我就不在这里进行更多的讲解了 如果有需要可以去develop官网上面继续了解 我们下面继续说ViewModel~ 加油 ~