无论页面处于什么状态,observeForever()都能收到通知。因此,在用完之后,一定要记得调用removeObserver()方法来移除观察者,否则会造成了内存泄漏。
ViewModel+LiveData实现Fragment间通信
==================================================================================================
ViewModel时储存在ViewModelStore里面的,而ViewModelStore是通过getViewModelStore获取的,我们只需要传入activity的ViewModelStoreOwner接口,那么多个fragment之间就获取的是同一个ViewModelStore了,那这样就能获取到同一个ViewModel了,然后利用LiveData观察者的特性即可实现数据之间的共享了。
1.定义ShareDataViewModel利用LiveData包装progress字段。
class ShareDataViewModel : ViewModel() {
val progress: MutableLiveData by lazy(LazyThreadSafetyMode.NONE) {
MutableLiveData(0)
}
}
2.定义相关布局文件,将两个fragment平放在一个布局里面。
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”
android:orientation=“vertical”
android:layout_width=“match_parent”
android:layout_height=“match_parent”>
<FrameLayout
android:id=“@+id/fl_id_1”
android:layout_width=“match_parent”
android:layout_height=“0dp”
android:layout_weight=“1”/>
<View
android:layout_width=“match_parent”
android:layout_height=“1dp”
android:background=“@color/design_default_color_primary”/>
<FrameLayout
android:id=“@+id/fl_id_2”
android:layout_width=“match_parent”
android:layout_height=“0dp”
android:layout_weight=“1”/>
定义fragment布局文件
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”
android:layout_width=“match_parent”
android:layout_height=“match_parent”>
<TextView
android:id=“@+id/tv_content”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_centerInParent=“true”
android:layout_above=“@id/seekbar”
android:text=“@string/app_name”/>
<SeekBar
android:id=“@+id/seekbar”
android:layout_width=“match_parent”
android:layout_height=“wrap_content”
android:layout_marginTop=“20dp”
android:max=“100”
android:layout_centerInParent=“true”/>
3.编写Fragment代码,实现具体的通信,注意ViewModelProvider传入activity。
class SeekBarFragment
@JvmOverloads
constructor(private val text: String = “”) : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return FragmentSeekbarBinding.inflate(layoutInflater).let {
fragmentSeekBarBinding ->
fragmentSeekBarBinding.tvContent.text = this.text
//注意这里使用activity,因为如果想共享数据需要使用同一个ViewModelStore。所以都是用activity的。
val liveDataProgress = ViewModelProvider(activity!!)[ShareDataViewModel::class.java].progress
//通过observe观察ViewModel中字段数据的变化,并在变化时得到通知
liveDataProgress.observe(this){
progress->
fragmentSeekBarBinding.seekbar.progress = progress
}
fragmentSeekBarBinding.seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(
seekBar: SeekBar?,
progress: Int,
fromUser: Boolean
) {
//当用户操作SeekBar时,更新ViewModel中的数据
liveDataProgress.value = progress
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
fragmentSeekBarBinding.root
}
}
}
5.编写activity代码,将fragment实例化,并放入activity中。
class ShareFragmentActivity : AppCompatActivity(){
lateinit var binding: ActivityFragmentContentBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initView()
}
private fun initView(){
binding = ActivityFragmentContentBinding.inflate(layoutInflater)
setContentView(binding.root)
supportFragmentManager.beginTransaction().add(binding.flId1.id,SeekBarFragment(“One-Fragment”)).commit()
supportFragmentManager.beginTransaction().add(binding.flId2.id,SeekBarFragment(“Two-Fragment”)).commit()
}
}
无论滑动上面的SeekBar还是下面的SeekBar,另一个Fragment的SeekBar一定会跟着滑动。在滑动SeekBar时,通过LiveData.setValue()方法,修改了ViewModel中LiveData包装的数据(progress字段)。由于Fragment通过LiveData.observe()方法监听了数据的变化,因此progress字段被修改后,Fragment能够第一时间收到通知并更新UI。
===============================================================================
LiveData.observe的源码:
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread(“observe”);
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
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);
}
上面说到过observe只能在主线程使用,observe里面第一步就用assertMainThread进行了主线程判断,如果当前运行的不是主线程的话,直接就抛异常了(assertMainThread内部实现在上面贴过了)。同理,LiveData的observeForever、removeObserver、removeObservers与setValue,也是一样的道理,在方法的第一步就用assertMainThread进行了判断,只能在主线程使用,否则就抛异常。
接下来看和生命周期相关的内容,如果当前生命周期是DESTROYED的话就直接return。LifecycleOwner传入到了LifecycleBoundObserver里面进行了包装,将包装后的对象和observer传入了mObservers(一个key value集合)进行保存,最后注册生命周期。所以看看LifecycleBoundObserver做了什么操作。
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();
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
@Override
void detachObserver() {
mOwner.getLifecycle().removeObserver(this);
}
}
先看onStateChanged方法(当生命周期变化的话会回调该方法),判断如果当前的生命周期是DESTROYED直接就移除了观察者。接下来判断当前生命周期的状态是否应该激活当前的观察者(只有观察者被激活才能接收到数据的变化),调用了shouldBeActive,而shouldBeActive则是判断了当前的生命周期是否大于等于STARTED,简单推理那应该就是生命周期在大于等于STARTED时才是激活状态。允许接收到值得变化。所以使用observe可接受到值得生命周期得范围应该时大于等于STARTED小于DESTROY。
接下来看activeStateChanged方法,我们假设此时生命周期大于STARTED,则传入得就是true。
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);
}
}
}
赋值状态为激活状态,changeActiveCounter改变当前激活状态得数量(这里不进入方法内分析了,该方法主要记录了处于激活状态得observe数量,然后判断如果激活状态得数量由从0到1得话调用了onActive方法,激活状态数量由1到0得话调用了onInactive方法。这两方法都是空方法,需要我们自己手动取实现,比如继承MutableLiveData或者LiveData取自己实现一个LiveData,具体要不要实现取决于自己得业务逻辑)。接下来就是判断如果在激活状态的话,就调用dispatchingValue(传入了this)开始分发事件。
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;
}
因为传入了initiator,所以就调用了considerNotify
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//调用到了observer得onChanged方法
observer.mObserver.onChanged((T) mData);
}
这个就很简单明了,满足激活状态下,shouldBeActive就是之前分析得大于等于STARTED,最后就调用了mObserver.onChanged就调用到了我们传入得Observer,实现了值得分发。
observeForever与observe得区别就是,observe使用得是LifecycleBoundObserver进行得包装,对生命周期进行了监控,而observeForever使用了AlwaysActiveObserver进行了包装
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer<? super T> observer) {
super(observer);
}
@Override
boolean shouldBeActive() {
return true;
}
}
里面没有对生命周期进行监控合适进行观察者移除销毁,且shouldBeActive永远返回true,所以无论页面处于什么状态,observeForever()都能收到通知。
再看看setValue得源码:
protected void setValue(T value) {
assertMainThread(“setValue”);
mVersion++;
mData = value;
dispatchingValue(null);
}
其实也没干啥,判断主线程,调用版本记录,赋值,返回就调用到了dispatchingValue方法,dispatchingValue不就和我们前面分析得一样嘛,只不过传入了空,这时候,走了else得逻辑从集合里面去除所有得observe进行调度分发而已。
看看postValue得源码:
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
//调度得主线程执行
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings(“unchecked”)
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//调用了setValue
setValue((T) newValue);
}
};
其实就是将异步线程调度到主线程执行,执行得mPostValueRunnable里面还是调用了setValue。
最后
在此为大家准备了四节优质的Android高级进阶视频:
架构师项目实战——全球首批Android开发者对Android架构的见解
附相关架构及资料
往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings(“unchecked”)
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//调用了setValue
setValue((T) newValue);
}
};
其实就是将异步线程调度到主线程执行,执行得mPostValueRunnable里面还是调用了setValue。
最后
在此为大家准备了四节优质的Android高级进阶视频:
架构师项目实战——全球首批Android开发者对Android架构的见解
附相关架构及资料
[外链图片转存中…(img-86SibNTr-1715666451843)]
往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!