Jetpack-生命周期组件库LiveData

LiveData#

用途#

可观察的数据存储类

关键: 是一种数据类型

优势#

  • 可感知其他组件的生命周期,如Activity、Fragment、Service

  • 只通知处于活跃状态的观察者;非活跃的观察者不会收到通知

  • 确保界面实时响应数据的变化—数据变化,会进入Observer#onStateChange回调

  • 不会发生内存泄漏–Observer会绑定到Lifecycle,其关联的组件销毁后,Observer会自我释放

  • 不会因为Activity停止导致crash–Observer处于非活跃状态,它不会收到任何LiveData事件

  • 数据始终保持最新状态–从非活跃状态变为活跃状态,Observer会收到最新的数据,后台Activity返回前台后会立刻接收最新的数据

  • 兼容系统配置更改–由于设备更改重新创建了Activity、Fragment,Observer会立即收到livedata的最新数据,这一切都不需要额外开发代码

  • 共享资源–使用单例模式扩展LiveData,以便于在整个App内共享数据。具体用法参考本节基本用法#共享值

生命周期#

  • onActive
  • onInactive

数据类型#

名称 用途
LiveData 抽象类,定义了setValue、postValue方法
MediatorLiveData LiveData的实现类,组合多个LiveData进行观察,也可以作为一个Livedata被Observer观察
MutableLiveData LiveData的实现类,泛型中声明即将存储的数据类型

基本用法#

livedata一般都存放于viewmodel类中,所以使用前先初始化viewmodel

1
nameViewModel = ViewModelProviders.of(this).get(NameViewModel.class);

LiveData封装在ViewModel里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class NameViewModel extends ViewModel {
private MutableLiveData<String> userName;

@Override
protected void onCleared() {
super.onCleared();
Log.e("NameViewModel", "onCleared: " );
}

public MutableLiveData<String> getUserName() {
if(userName == null){
userName = new MutableLiveData<>();
}
return userName;
}
}

设置值#

通过viewmodel#getUserName拿到livedata,再通过lviedata的setvalue方法设置数值

1
nameViewModel.getUserName().setValue("jordan " + aLong + " 号");

订阅值#

通过viewmodel#getUserName拿到livedata,再通过lviedata的observer方法观察数值的改变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Observer<String> nameObserver = new Observer<String>() {
@Override
public void onChanged(String s) {
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.append("s:" + s);
textView.append("\n");
}
});
}
};
// 设置LifecycleOwner 和观察者
nameViewModel.getUserName().observe(this, nameObserver);

问:postValue与setValue区别

如果处于主线程中,可以使用 setValue(T) 方法更新 LiveData 对象

如果在子线程中,可以使用postValue(T) 方法来更新 LiveData 对象

问:不考虑页面生命周期,如果先设置值,后observer,会进入onchange回调吗?

答:会进入onchange回调

组合订阅#

看一下组合订阅的用法

  • 两次addSource,为MediatorLiveData传入了2个LiveData实现类,同时为每个livedata设置了Observer
  • MediatorLiveData设置观察者Observer
  • 在任意一个livedata收到onChanged回调时,触发MediatorLiveData的set方法,设置值
  • MediatorLiveData的observer会收到上一步MediatorLiveData#set方法的通知
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
		MediatorViewModel mediatorViewModel = ViewModelProviders.of(this).get(MediatorViewModel.class);
MediatorLiveData mediatorLiveData = mediatorViewModel.getData();
mediatorLiveData.addSource(liveData1, new Observer() {
@Override
public void onChanged(Object o) {
mediatorLiveData.setValue(o);
}
});
mediatorLiveData.addSource(liveData2, new Observer() {
@Override
public void onChanged(Object o) {
mediatorLiveData.setValue(o);
}
});


mediatorLiveData.observe(this, new Observer() {
@Override
public void onChanged(Object o) {
Log.e(TAG, "监听到了数据源1、2的变化:onChanged: "+ o.toString());
textView.append("value:" + o.toString());
textView.append("\n");
// if(){
// mediatorLiveData.removeSource(liveData1);
// }else {
// mediatorLiveData.removeSource(liveData2);
// }
}
});

共享值.#

定义一个单例LiveData

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
public class StockLiveData extends LiveData<BigDecimal> {
private static StockLiveData sInstance;
private StockManager stockManager;

private SimplePriceListener listener = new SimplePriceListener() {
@Override
public void onPriceChanged(BigDecimal price) {
setValue(price);
}
};

@MainThread
public static StockLiveData get(String symbol) {
if (sInstance == null) {
sInstance = new StockLiveData(symbol);
}
return sInstance;
}

private StockLiveData(String symbol) {
stockManager = new StockManager(symbol);
}

@Override
protected void onActive() {
stockManager.requestPriceUpdates(listener);
}

@Override
protected void onInactive() {
stockManager.removeUpdates(listener);
}
}

其他Fragment、Activity可以这样使用它

1
2
3
4
5
6
7
8
9
public class MyFragment extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> {
// Update the UI.
});
}
}

在多个Activity、Fragment的任意一处通过StockLiveData#get得到的返回值都是全局唯一的。

疑问#

  1. livedata存放在App进程还是系统进程?App进程销毁后重新创建能恢复之前的数据吗?
  2. 永久的Observer有什么用?

问题3:value不变,调用setValue,会进入Observer的回调吗?

答:会,LiveData不会判断相等

问题4:postvalue是如何通知主线程刷新的?

使用Handler.createAsync创建了异步Handler,持有主线程的Looper

使用异步Handler发出的Message都是异步消息,结合view.requestLayout设置的消息屏障,可以让MessageQueue优先执行异步消息,后执行同步消息

消息屏障相关:https://www.cnblogs.com/huan89/p/14551926.html

下图是我梳理的postValue的执行过程,使用Handler发出异步消息,优先于主线程的同步消息执行。这样可以做到在下一次界面刷新之前(每隔16.6ms)设置数据。

livedata#setvalue

问题5:postValue一定会进入observer回调吗?

答:不一定,取决于许多因素

  1. 生命周期的状态是否处于活跃状态:startedresumed。如果处于这两种状态,则会进入observer#onChanged回调;如果不处于,则不会进入回调
点击查看
-------------------本文结束 感谢您的阅读-------------------