JetPack之二:LiveData
1.什么是LiveData?
LiveData是一种类,持有可被调查的数据。LiveData是一种可感知生命周期的组件,它是根据lifecycle组件的,意味着该组件注重其他app组件的生命周期,如Activity、Fragment、Service。该组件能确保,仅仅在Activity\Fragment\Service等组件都处于活泼的生命周期状况的时分,才去更新app组件。Activity、Fragment不必担心会出现内存走漏,在Activity、Fragment销毁时,LiveData会主动免除其注册关系。
2.为什么要用Livedata?
-
LiveData能确保UI和数据状况相符
由于是调查者形式,LiveData会在生命周期状况改动时,通知调查者 能够在调查者目标中进行UI的更新操作
-
LiveData没有内存走漏
调查者和Lifecycle目标绑定,能在销毁时主动免除注册
-
LiveData不会给已经中止的Activity发送事情
假设调查者处于非活泼状况,LiveData不会再发送任何事情给这些Observer目标
-
LiveData能确保不再需求手工对生命周期进行处理
UI组件仅仅需求对相关数据进行调查 LiveData主动处理生命周期状况改动后,需求处理的代码。
-
LiveData能确保数据最新
一个非活泼的组件进入到活泼状况后,会立即获取到最新的数据 不必担心数据问题
-
LiveData在反正屏切换等Configuration改动时,也能确保获取到最新数据
例如Acitivty、Fragment由于屏幕选装导致重建, 能立即接收到最新的数据
-
LiveData能资源共享
假设将LiveData目标扩大,用单例形式将体系服务进行包裹。这些服务就能够在app中共享。 只需求LiveData和体系服务connect,其他调查者只需求监视LiveData就能获取到这些资源
3.简略运用
首要在你的模块build.gradle里边添加依靠:
dependencies {
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
}
最简略的一种运用是MutableLivedata:
class MainActivity : AppCompatActivity() {
private val mLivedata = MutableLiveData<String>()//1
private val mBinding: ActivityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(mBinding.root)
mLivedata.observe(this) {//2
mBinding.textView.text = it
}
var num = 0
mBinding.button.setOnClickListener {
mLivedata.value = num++.toString()//3
}
}
}
我这儿用了viewbinding代替了findviewbyid。首要在1处定义了mLivedata,类型是MutableLiveData,MutableLiveData是LiveData的子类,露出出了setValue和postValue两个办法。然后在2处订阅,传入的第一个参数是具有生命周期的组件,一般是Activity或许Fragment或许是fragment里边的veiw,第二个参数是收到数据之后的回调,这儿便是用一个textVeiw将值呈现了出来。然后在3处给一个按钮设置监听,每按一次就发送一个数据。大约的用法仍是比较简略的。
再看几个比较进阶的用法:
假设咱们想要在LiveData目标分发给调查者之前对其间存储的值进行更改,能够运用Transformations.map()和Transformations.switchMap()
map()是在数据分发之前进行一些处理,而switchMap更多是在多条LiveData下挑选一条LiveData:
class MainActivity : AppCompatActivity() {
private val mLivedata = MutableLiveData<Int>()
private val mBinding: ActivityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(mBinding.root)
mLivedata.observe(this) {
mBinding.textView.text = it.toString()
}
var num = 0
mBinding.button.setOnClickListener {
mLivedata.value = num++
}
Transformations.map(mLivedata) {//1
return@map it - 10000
}.observe(this) {
Toast.makeText(this, it.toString(), Toast.LENGTH_SHORT).show()
}
Transformations.switchMap(mLivedata) {//2
val mutableLiveData1 = MutableLiveData<String>()
val mutableLiveData2 = MutableLiveData<String>()
mutableLiveData1.value = (it + 10).toString()
mutableLiveData2.value = (it - 10).toString()
if (it < 10) return@switchMap mutableLiveData1
else return@switchMap mutableLiveData2
}.observe(this) {
mBinding.textView2.text = it
}
}
}
用法很简略,在1处运用Transformations.map对值进行处理,这儿便是对原值减10000,然后observer新的LiveData,这儿便是弹一个吐司。在2处Transformations.switchMap(mLivedata)对原值进行判别,大于10就回来mutableLiveData1,不然mutableLiveData2,然后对新的LiveDataObserver显现在TextView上面。
这两种用法不是很常用。还有一种用法,当有多条LiveData时,咱们需求合并成一条LiveData,这时分能够用MediatorLiveData:
class MainActivity : AppCompatActivity() {
private val mediatorLiveData = MediatorLiveData<Int>()
private val mutableLiveData1=MutableLiveData<Int>()
private val mutableLiveData2 = MutableLiveData<Int>()
private val mBinding: ActivityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(mBinding.root)
var num = 0
mBinding.button.setOnClickListener {
mutableLiveData1.value = num+20
}
mBinding.button2.setOnClickListener {
mutableLiveData2.value = num-20
}
mediatorLiveData.addSource(mutableLiveData1){
mediatorLiveData.value = it
}
mediatorLiveData.addSource(mutableLiveData2){
mediatorLiveData.value = it
}
mediatorLiveData.observe(this){
mBinding.textView.text = it.toString()
}
}
}
首要咱们创建了两条MutableLiveData,然后定义了一个MediatorLiveData,用了两个按钮,分别发送LiveData1和LiveData2的值,再将他们加入到MediatorLiveData,MediatorLiveData本身也是LiveData,再对其Observer这样就达到合并多条LiveData的值。到这儿LiveData的一些简略用法便是这些了。那大家有没有疑问,Activity是怎样感知LiveData发送了值的?LiveData为什么不会形成内存走漏?咱们来看看它的源码,把它扒个精光。
4.原理
首要咱们看LiveData的源码和看LifeCycle的源码相同,从咱们写的代码下手,那便是Observer:
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {//1
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);//2
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);//3
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);//4
}
被注解在主线程运转,1处的条件判别阐明咱们在Destroy去Observer是没用的,2处把咱们传进来的owner和observer封装成了LifecycleBoundObserver,它的作用咱们等会分析,3处把wrapper添加进了一个map里边,阐明咱们的liveData是能够有多处Observer的,之后是一些安全判别,最终在4处将咱们的wrapper注册到lifeCycle,这不便是咱们lifeCycle里边学的嘛,那这个LifecycleBoundObserver必定完成了LifeCycleObserver咱们看一看:
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
super(observer);
mOwner = owner;
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();//1
if (currentState == DESTROYED) {//2
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while (prevState != currentState) {//3
prevState = currentState;
activeStateChanged(shouldBeActive());//4
currentState = mOwner.getLifecycle().getCurrentState();
}
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
果然,完成了LifecycleEventObserver来感知咱们的activity生命周期,那必定在生命周期回调的办法onStateChanged里边做了文章,咱们看,在1处获取了activtiy当时的生命周期状况,2处,处于destroy的话就移除Observer,这阐明了当我 们的activtiy销毁的时分livedata会主动免除监听,所以才不会形成内存走漏。然后在3处判别假设当时状况和即将产生的状况不相同就履行activeStateChanged(shouldBeActive()),那咱们看看shouldBeActive:
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
public enum State {
/**
* Destroyed state for a LifecycleOwner. After this event, this Lifecycle will not dispatch
* any more events. For instance, for an {@link android.app.Activity}, this state is reached
* <b>right before</b> Activity's {@link android.app.Activity#onDestroy() onDestroy} call.
*/
DESTROYED,
/**
* Initialized state for a LifecycleOwner. For an {@link android.app.Activity}, this is
* the state when it is constructed but has not received
* {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} yet.
*/
INITIALIZED,
/**
* Created state for a LifecycleOwner. For an {@link android.app.Activity}, this state
* is reached in two cases:
* <ul>
* <li>after {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} call;
* <li><b>right before</b> {@link android.app.Activity#onStop() onStop} call.
* </ul>
*/
CREATED,
/**
* Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state
* is reached in two cases:
* <ul>
* <li>after {@link android.app.Activity#onStart() onStart} call;
* <li><b>right before</b> {@link android.app.Activity#onPause() onPause} call.
* </ul>
*/
STARTED,
/**
* Resumed state for a LifecycleOwner. For an {@link android.app.Activity}, this state
* is reached after {@link android.app.Activity#onResume() onResume} is called.
*/
RESUMED;
/**
* Compares if this State is greater or equal to the given {@code state}.
*
* @param state State to compare with
* @return true if this State is greater or equal to the given {@code state}
*/
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
}
便是将当时状况和START状况相减,大于等于0为true,那也便是START和RSUME这两个状况,LiveData才有效,这也契合用户运用习惯,activtiy也是在START和RSUME呈现页面。
再来看看activeStateChanged():
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
changeActiveCounter(mActive ? 1 : -1);
if (mActive) {
dispatchingValue(this);
}
}
首要判别mActive是否和newActive相等,mActive初始状况是不活越的,为flase,所以在newActive为false时也便是activty为不活越的状况就会直接回来而不会直接分发值,之后假设是活泼的状况就changeActiveCounter(mActive ? 1 : -1);改动activeCounter的值,这个咱们用不到,不必管,主要是dispatchingValue,假设是活泼状况就分发值,而且将当时的this传进去,咱们看看:
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {//1
considerNotify(initiator);
initiator = null;
} else {//2
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
主要操作鄙人面的do while循环里边,判别咱们传进来的ObserverWrapper是否为空,不为空就履行considerNotify(initiator);为空就循环遍历咱们一开端observer里边添加的observerWrapper,为什么是for循环?由于咱们刚才说了,一个liveData能够被多个生命周期组件观测。所以在这儿为null的时分从Observers这个map里边去拿。咱们看看considerNotify(initiator);
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {//1
return;
}
// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
//
// we still first check observer.active to keep it as the entrance for events. So even if
// the observer moved to an active state, if we've not received that event, we better not
// notify for a more predictable notification order.
if (!observer.shouldBeActive()) {//2
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {//3
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
在1处判别,不活越就直接结束。在2处是一些边界处理,上面的注释也说了当activty生命周期改动时,还未来的及改动mActive的值,此刻应该先更改活泼的状况再分发值,这其实不重要咱们一般碰不到。然后在3处判别前次的version是否比当时的mVersion大,不然再鄙人面更新mLastVersion,而且履行onChange,也便是咱们再observer办法里边传进来的lamda表达式。一开端mLastVersion和mVersion都是为-1的,所以不会履行下面的回调。到这儿Observer办法咱们从始至终理解了一边。那一开端咱们的onChanged不会回调,那什么时分会呢?答案在setValue里边,咱们看一看:
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
注解阐明,setValue是在主线程履行,然后mVersion++;由于一开端mVersion是等于mLastVersion的,现在++了,必定比mLastVersion大,之后dispatchingValue(null),注意看,这时分传入的值为null,也便是咱们刚刚说的dispatchingValue传入值为null的时分会for遍历所有的Oberver然后considerNotify,也就到了:
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
//
// we still first check observer.active to keep it as the entrance for events. So even if
// the observer moved to an active state, if we've not received that event, we better not
// notify for a more predictable notification order.
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
这时分mVsersion小于mLastVersion,所以便是会履行onChanged,也便是咱们传进来的lamda表达式,这就说清楚了为什么每次setValue,activity都能收到值得原因啦。那咱们再看看liveData的另外一个办法,postValue:
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;//1
mPendingData = value;//2
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);//3
}
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
setValue((T) newValue);//4
}
};
postValue是用来在子线程向liveData发送值的,首要判别mPendingData的值是不是还没设置过,是的话才会分发值,而且将value赋给mPendingData,然后将mPostValueRunnable扔到主线程运转,mPostValueRunnable里边把mPendingData赋值给newValue,再将mPendingData置为未设置,最终履行的便是setValue;其实postToMainThread也便是用Handler发送一个消息到主线程:
@Override
public void postToMainThread(Runnable runnable) {
if (mMainHandler == null) {
synchronized (mLock) {
if (mMainHandler == null) {
mMainHandler = createAsync(Looper.getMainLooper());
}
}
}
//noinspection ConstantConditions
mMainHandler.post(runnable);
}
那你们有没有发现一个问题,已然setValue是用Handler发一个消息到主线程,而Handler消息是个队列,那假设我同时postValue屡次,但由于前面的消息还没处理完,mPostValueRunnable还没有运转,mPendingData还没有被置为NOT_SET,postTask就一向为false,所以后面的postValue直接return了,形成我中心postValue的值直接被覆盖了,从而只收到了最新postValue的值,形成了中心值丢失的问题。解决问题很简略,自己切换到主线程然后用setValue,setValue是不会丢值得。
至此,LiveData的源码分析的差不多了,至于liveData的其他什么办法比如说,observerForever,rmoveobserverForever,都比较简略了,而且也不常用,相信你把这些根底的搞懂,其他的不会太难理解。
LiveData数据倒灌
数据倒灌简而言之便是咱们并没有给livedata设置数据而收到了旧的数据。
LiveData的数据倒灌问题。便是当咱们用LiveData去发送数据产生事情的时分,你会发现事情会屡次产生。咱们知道咱们的LiveData是在onCreate去Observe的,而且经过源码咱们知道,Observer的时分内部会new 一个LifecycleBoundObserver,而且将observe.mLastVersion置为默认值-1,可是此刻LiveData的mVersion是没有改动的。而咱们的LiveData一般是放在viewmoodel中的,liveData必定比Activity活的时间长,假设咱们在onCreate里去Observe而且给LiveData发送数据,在此过后mVersion是++了的也便是说mVersion至少是大于初始值-1的,假设此刻Activtiy重建,重走onCreate办法,此刻mVersion是保存在LiveData里边,LiveData是在viewmodel里边,LiveData的实例没有被重建,可是从头走了onCreate,从头Observe了,又从头new了一个LifecycleBoundObserver,也便是mLastVersion为-1,所以此刻mLastVersion<mVersion,会回调咱们的onChanged()。这便是为什么用LiveData发送事情会被消费屡次。而数据多贴一遍咱们也不会觉得有问题。可是这其实也不是LiveData的一个bug,liveData规划理念便是专注于给UI层发送数据,关于事情这种咱们更应该运用flow或许rxjava。可是把LiveData改改也能用:
class SingleLiveData<T> : MutableLiveData<T>() {
private val mPending = AtomicBoolean(false)
@MainThread
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
if (hasActiveObservers()) {
Log.w(
"SingleLiveEvent",
"Multiple observers registered but only one will be notified of changes."
)
}
super.observe(owner) { t ->
if (mPending.compareAndSet(true, false)) {
observer.onChanged(t)
}
}
}
@MainThread
override fun setValue(t: T?) {
mPending.set(true)
super.setValue(t)
}
@MainThread
fun call() {
value = null
}
}
AtomicBoolean是经过原子方式更新 boolean 值,能够确保线程安全。这也是官方Demo里边的解决方案,用个boolean记载一次value是否被消费。一次setValue对应一次onChanged而且这个Boolean值是保存在LiveData中的,这样就能用于发送事情了。
其实最佳的解决方案便是不要用LiveData去发送“事情”。
好了以上便是LiveData的一些介绍,喜爱的点点关注点点赞哟。