Jetpack的MVVM本身没有错,错在开发者的某些使用不当。本文将分享那些AAC中常见的错误用法,以帮助大家打造更健康的应用架构Fragment作为LifecycleOwner的问题 MVVM的核心是数据驱动UI,在Jetpack中,这一思想体现在以下场景:Fragment通过订阅ViewModel中的LiveData以驱动自身UI的更新 关于订阅的时机,一般会选择放到onViewCreated中进行,如下:overridefunonViewCreated(view:View,savedInstanceState:Bundle?){super。onViewCreated(view,savedInstanceState)viewModel。liveData。observe(this){Warning:UsefragmentastheLifecycleOwnerupdateUI(it)}} 我们知道订阅LiveData时需要传入LifecycleOwner以防止泄露,此时一个容易犯的错误是使用Fragment作为这个LifecycleOwner,某些场景下会造成重复订阅的Bug。 做个实验如下:valhandlerHandler(Looper。getMainLooper())classMyFragment1:Fragment(){valdataMutableLiveDataInt()overridefunonViewCreated(view:View,savedInstanceState:Bundle?){super。onViewCreated(view,savedInstanceState)tv。setOnClickListener{parentFragmentManager。beginTransaction()。replace(R。id。container,MyFragment2())。addToBackStack(null)。commit()handler。post{data。value1}}data。observe(this,Observer{Log。e(fragment,count:{data。value})})} 当跳转到MyFragment2然后再返回MyFragment1中时,会打出输出两条logEfragment:count:1Efragment:count:1原因分析 LiveData之所以能够防止泄露,是当LifecycleOwner生命周期走到DESTROYED的时候会remove调其关联的ObserverLiveData。javaOverridepublicvoidonStateChanged(LifecycleOwnersource,Lifecycle。Eventevent){if(mOwner。getLifecycle()。getCurrentState()DESTROYED){removeObserver(mObserver);}activeStateChanged(shouldBeActive());} 前面例子中,基于FragmentManagerreplace的页面跳转,使得MyFragment1发生了从BackStack的出栈入栈,由于Framgent实例被复用并没有发生onDestroy,但是Fragment的View的重建导致重新onCreateView,这使得Observer被add了两次,但是没有对应的remove。 所以归其原因,是由于Fragment的Lifecycle与FragmentmView的Lifecycle不一致导致我们订阅LiveData的时机和所使用的LivecycleOwner不匹配,所以在任何基于replace进行页面切换的场景中,例如ViewPager、Navigation等会发生上述bug 解决方法 明白了问题原因,解决思路也就清楚了:必须要保证订阅的时机和所使用的LifecycleOwner相匹配,即要么调整订阅时机,要么修改LifecycleOwner 在onCreate中订阅 思路一是修改订阅时机,将订阅提前到onCreate,可以保证与onDestory的成对出现,但不幸的是这会带来另一个问题。 当Fragment出入栈造成View重建时,我们需要重建后的View也能显示最新状态。但是由于onCreate中的订阅的Observer已经获取过LiveData的最新的Value,如果Value没有新的变化是无法再次通知Obsever的 在LiveData源码中体现在通知Obsever之前对mLastVersion的判断:LiveData。javaprivatevoidconsiderNotify(ObserverWrapperobserver){if(!observer。mActive){}if(!observer。shouldBeActive()){observer。activeStateChanged(false);}if(observer。mLastVersionmVersion){Value已经处于最新的}observer。mLastVersionmVnoinspectionuncheckedobserver。mObserver。onChanged((T)mData);} 正是为了保证重建后的View也能刷新最新的数据,我们才在onViewCreated中完成订阅。因此只能考虑另一个思路,替换LifecycleOwner 使用ViewLifecycleOwner Support28或AndroidX1。0。0起,Fragment新增了getViewLifecycleOwner方法。顾名思义,它返回一个与FragmentmView相匹配的LifecycleOwner,可以在onDestroyView的时候走到DESTROYED,删除onCreateView中注册的Observer,保证了addremove的成对出现。 看一下源码,原理非常简单Fragment。javavoidperformCreateView(NonNullLayoutInflaterinflater,NullableViewGroupcontainer,NullableBundlesavedInstanceState){。。。mViewLifecycleOwnernewLifecycleOwner(){OverridepublicLifecyclegetLifecycle(){if(mViewLifecycleRegistrynull){mViewLifecycleRegistrynewLifecycleRegistry(mViewLifecycleOwner);}returnmViewLifecycleR}};mViewLifecycleRmViewonCreateView(inflater,container,savedInstanceState);if(mView!null){InitializetheLifecycleRegistryifneededmViewLifecycleOwner。getLifecycle();TheninformanyObserversofthenewLifecycleOwnermViewLifecycleOwnerLiveData。setValue(mViewLifecycleOwner);mViewLifecycleOwnerLiveData在后文介绍}else{。。。}} 基于mViewLifecycleRegistry创建mViewLifecycleOwner,CallSuperpublicvoidonViewStateRestored(NullableBundlesavedInstanceState){calledwhenonCreateViewif(mView!null){mViewLifecycleRegistry。handleLifecycleEvent(Lifecycle。Event。ONCREATE);}}CallSuperpublicvoidonDestroyView(){if(mView!null){mViewLifecycleRegistry。handleLifecycleEvent(Lifecycle。Event。ONDESTROY);}} 然后在onCreateView和onDestroyView时,推进到合适的生命周期。 getViewLifecycleOwnerLiveData 顺道提一下,与getViewLifecycleOwner同时新增的还有getViewLifecycleOwnerLiveData。从前面贴的源码中对mViewLifecycleOwnerLiveData的使用,应该可以猜出它的作用:它是前文讨论的思路1的实现方案,即使在onCreate中订阅,由于在onCreateView中对LiveData进行了重新设置,所以重建后的View也可以更新数据。TheninformanyObserversofthenewLifecycleOwnermViewLifecycleOwnerLiveData。setValue(mViewLifecycleOwner); 需要特别注意的是,根据MVVM最佳实践,我们希望由ViewModel而不是Fragment持有LiveData,所以不再推荐使用getViewLifecycleOwnerLiveData最后:StateFlow与lifecycleScope 前面都是以LiveData为例介绍对ViewLifecycleOwner的使用,如今大家也越来越多的开始使用协程的StateFlow,同样要注意不要错用LifecycleOwner 订阅StateFlow需要CoroutineScope,AndroidX提供了基于LifecycleOwner的扩展方法valLifecycleOwner。lifecycleScope:LifecycleCoroutineScopeget()lifecycle。coroutineScope 当我们在Fragment中获取lifecycleScope时,切记要使用ViewLifecycleOwnerclassMyFragment:Fragment(){valviewModel:MyViewModelbyviewModel()overridefunonViewCreated(view:View,savedInstanceState:Bundle?){super。onViewCreated(view,savedInstanceState)使用viewLifecycleOwner的lifecycleScopeviewLifecycleOwner。lifecycleScope。launch{viewLifecycleOwner。repeatOnLifecycle(Lifecycle。State。STARTED){viewModel。someDataFlow。collect{updateUI(it)}}}}} 注意此处出现了一个repeatOnLifecycle(。。。),这跟本文无关,但是将涉及到下一宗罪的剧情,敬请期待。最后 在这里就还分享一份由大佬亲自收录整理的Android学习PDF架构视频面试文档源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这些都是我现在闲暇时还会反复翻阅的精品资料。里面对近几年的大厂面试高频知识点都有详细的讲解。相信可以有效地帮助大家掌握知识、理解原理,帮助大家在未来取得一份不错的答卷。 当然,你也可以拿去查漏补缺,提升自身的竞争力。 真心希望可以帮助到大家,Android路漫漫,共勉! 如果你有需要的话,只需私信我【进阶】即可获取