Android暗中观察组件LiveData

Android JetPack组件之LiveData

在这里插入图片描述

简介

和上一篇Lifecycle组件一样,LiveData也是一个观察者机制的东西,订阅者订阅LiveData后,LiveData数据发生变化,就会通知到订阅者;


使用步骤

  1. 创建LiveData数据
  2. 加入订阅者到LiveData中去
  3. 改变LiveData的值
  4. 触发通知到订阅者

伪代码如下:

6. val myLiveData = MutableLiveData<String>()
7. myLiveData.observe(LifecycleOwner, Observer {
    
    
            void onChanged(String t){
    
    
				Log.i("tag", t)
			}
        })
8. myLiveData.postValue("new value")
9. 打印执行new value

上面代码就是LiveData的一个简单使用,那么它背后的原理如何,请看下分析


实现原理

MutableLiveData

MutableLiveData类是LiveData类的子类,基本和LiveData一样,没有做特别的改变;当然除了MutableLiveData子类外,还有RoomTrackingLiveData类,也是LiveData的另一个实现,RoomTrackingLiveData主要是用于Database相关的操作,这里我们只分析MutableLiveData,其代码如下:

public class MutableLiveData<T> extends LiveData<T> {
    
    
    public MutableLiveData(T value) {
    
    
        super(value);
    }
    public MutableLiveData() {
    
    
        super();
    }
    @Override
    public void postValue(T value) {
    
    
        super.postValue(value);
    }
    @Override
    public void setValue(T value) {
    
    
        super.setValue(value);
    }
}

为LiveData添加订阅者

liveData添加订阅者,主要是通过observer方法添加进去,需要注意的是第一个参数必须是LifecycleOwner类型,表示订阅者自己本身也必须有一个状态,在订阅者死亡后LiveData就不在继续给你同步消息了,添加observer的逻辑如下图:
在这里插入图片描述
首先,在Activity里面添加订阅者到liveData,因为Activity本身就实现了LifecycleOwner接口,所以第一个参数为this即可,第二个就是Observer对象;然后就进入到LiveData类的observer里面去,如下代码:

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    
    
   如果添加进入的owner已经都是DESTROYED状态,那么久没必要在添加进来了
   if (owner.getLifecycle().getCurrentState() == DESTROYED) {
    
    
       // ignore
       return;
   }
   内部封装类,将owner和Observer参数封装在一起
   LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
   ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
   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);
}
LifecycleBoundObserver实现了LifecycleEventObserver,方便订阅者将自己的状态同步过来
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
    
    
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
    
    
            super(observer);
            mOwner = owner;
        }
        订阅者那边如果生命状态发生变化会把状态通知过来
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
    
    
            如果订阅者转头为DESTROYED,那就把这个订阅者从livedata中删除掉
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
    
    
                removeObserver(mObserver);
                return;
            }
            状态通知下去,
            activeStateChanged(shouldBeActive());
        }
        这块代码主要作用是订阅者的状态由false变为true的时候,要给他来一次事件发布
		void activeStateChanged(boolean newActive) {
    
    
			如果状态都一样,那么没必要把数据在发布给订阅者
            if (newActive == mActive) {
    
    
                return;
            }
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            /*省略部分代码*/
            如果存活就把value发送给订阅者
            if (mActive) {
    
    
                dispatchingValue(this);
            }
        }
    }

mObservers.putIfAbsent 将订阅者添加到mObservers里面,mObservers是SafeIterableMap类型,就是一个双链表数据结构,存储元素类型为Entry:

public V putIfAbsent(@NonNull K key, @NonNull V v) {
    
    
    Entry<K, V> entry = get(key);
    if (entry != null) {
    
    
        return entry.mValue;
    }
    put(key, v);
    return null;
}

protected Entry<K, V> put(@NonNull K key, @NonNull V v) {
    
    
    Entry<K, V> newEntry = new Entry<>(key, v);
    mSize++;
    if (mEnd == null) {
    
    
        mStart = newEntry;
        mEnd = mStart;
        return newEntry;
    }
    mEnd.mNext = newEntry;
    newEntry.mPrevious = mEnd;
    mEnd = newEntry;
    return newEntry;

}

代码很简单,直接看就行;
最后在observer方法最后一句owner.getLifecycle().addObserver(wrapper),也就是会把这个wrapper添加到订阅者(Activity)那边去,为什么这么做呢?主要是添加过去后,方便Activity生命周期变化,进行状态同步过来


更新LiveData数据

在MutableLiveData中有set和post两种方法更新,post可以在非主线程使用,而set必须在子线程使用,我们用post来看看:

protected void postValue(T value) {
    
    
    boolean postTask;
    多线程处理mPendingData,所以必须加锁
    synchronized (mDataLock) {
    
    
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    postTask为false,说明mPendingData已经有值,并且正在把值分发给订阅者;
    所以这里不需要再次分发,直接返回,只修改mPendingData即可
    if (!postTask) {
    
    
        return;
    }
    开始在主线程执行mPostValueRunnable
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

上述代码主要是先获取同步锁,检查mPendingData是否已经设置,更新mPendingData,如果已经改变,说明消息发布任务已启动,无须再次启动,然后进入postToMainThread方法看看:

@Override
public void postToMainThread(Runnable runnable) {
    
    
    if (mMainHandler == null) {
    
    
        synchronized (mLock) {
    
    
            if (mMainHandler == null) {
    
    
            	获取主线程的Looper,创建一个异步的Handler
                mMainHandler = createAsync(Looper.getMainLooper());
            }
        }
    }
    handler发送runnable任务
    mMainHandler.post(runnable);
}

这里线程切换就是handler来实现的,需要了解Android handle机制看这里
最后,再回头看看这个Runnable是什么任务?

private final Runnable mPostValueRunnable = new Runnable() {
    
    
@SuppressWarnings("unchecked")
@Override
public void run() {
    
    
    Object newValue;
    写入值和发送值不能同时处理,所以必须要用同一把锁锁住
    synchronized (mDataLock) {
    
    
    	把值拷贝到新的newValue去,同时要设置mPendingData为NOT_SET,
    	方便下次值的写入
        newValue = mPendingData;
        mPendingData = NOT_SET;
    }
    setValue((T) newValue);
}
};

@MainThread
protected void setValue(T value) {
    
    
    assertMainThread("setValue");
    没写入一次值,要为其赋一个版本号
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

void dispatchingValue(@Nullable ObserverWrapper initiator) {
    
    
    if (mDispatchingValue) {
    
    
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
    
    
        mDispatchInvalidated = false;
        if (initiator != null) {
    
    
            considerNotify(initiator);
            initiator = null;
        } else {
    
    
        	遍历所有订阅者,挨个取出来把新值发给他们
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
    
    
                这里就是消息分发    
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
    
    
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

private void considerNotify(ObserverWrapper observer) {
    
    
	如果这个订阅者mActive为false,也就是小于STARTED状态,就没必要消息分发了
    if (!observer.mActive) {
    
    
        return;
    }
    这里检查的不是订阅者,是订阅者那边的LifecycleOwner的状态,这个状态比上面的可靠
    并把状态同步给订阅者,此时订阅者状态是正确的,而且也没必要去消息分发;
    这里为什么要这么做?是因为订阅者observer可能还不是最新的状态,所以需要把LifecycleOwner
    同步给订阅者,以免做无用的消息分发
    if (!observer.shouldBeActive()) {
    
    
        observer.activeStateChanged(false);
        return;
    }
    这里搞不懂,mLastVersion都是为啥要这么多,会出现大于的情况吗,我觉得不会出现,
    因为	mLastVersion都是mVersion赋值给他的,他肯定比mVersion小啊
    if (observer.mLastVersion >= mVersion) {
    
    
        return;
    }
    observer.mLastVersion = mVersion;
    执行onChanged方法,就是最初的Observer的回调函数
    observer.mObserver.onChanged((T) mData);
}

以上消息分发就完成了,做个小结:

  1. 注意post和set的区别,主线程和任意线程
  2. post会出现多线程共同使用mPendingData的情况,所以要加锁,并且使用完后要mPendingData重置为NOT_SET
  3. 最后就是在消息通知时要先判断一下订阅者状态,小于STARTED不需要分发,因为订阅者状态可能会有延迟,就把订阅者所属的LifecycleOwner的状态给他同步过来,false也不往下发
  4. 最后更新版本号,然后执行onChanged

销毁订阅者

订阅者自身状态DESTROYED死亡后,需要将自己从LiveData中remove掉,主要发生在LiveData的内部类LifecycleBoundObserver中的onStateChanged方法里面,因为LifecycleBoundObserver实现了LifecycleEventObserver接口,在订阅者那边LifecycleOwner提前在LiveData的observer方法最后将LifecycleBoundObserver添加进去了,也就是添加到了LifecycleOwner的订阅者集合,所以当LifecycleOwner状态变化时,会将状态同步给他的订阅者,也就是LifecycleBoundObserver,当处于DESTROY时,就会将同步调用LifecycleBoundObserver的onStateChanged方法,方法如下:

public void onStateChanged(@NonNull LifecycleOwner source,
    @NonNull Lifecycle.Event event) {
    
    
    if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
    
    
        removeObserver(mObserver);
        return;
    }
    activeStateChanged(shouldBeActive());
}

@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
    
    
    assertMainThread("removeObserver");
    ObserverWrapper removed = mObservers.remove(observer);
    if (removed == null) {
    
    
        return;
    }
    removed.detachObserver();
    removed.activeStateChanged(false);
}

上面的文字描述比较复杂,难理解,你要理解的是LifecycleBoundObserver是对LiveData的订阅封装类,LiveData添加了LifecycleBoundObserver,用于消息通知;而LifecycleOwner也添加了这个LifecycleBoundObserver,这边添加是为了生命状态同步,需要配合Android Lifecycle疑问看看;大致简图如下:
在这里插入图片描述


总结

LiveData采用观察者模式,一有数据更新时,会发布给订阅者;与很好的与视图解耦,也无须担心内存泄漏的问题,除非LiveData本身持有其他的外部引用导致自身无法释放;因为在Activity这端,会实时的把自身状态同步给LifecycleBoundObserver,以便在DESTROY状态下,liveData会自动remove掉订阅者

猜你喜欢

转载自blog.csdn.net/jackzhouyu/article/details/106025136