FragmentManagerViewModel与Fragment的ViewModel
现在FragmentManagerViewModel可以在Activity重建时恢复,那么它和Fragment里的ViewModel又是如何关联的呢?
FragmentManagerViewModel 里有个成员变量:
private final HashMap<String, ViewModelStore> mViewModelStores = new HashMap<>();
在Fragment里声明ViewModel:
private val vm by viewModels()
查看viewModels调用链,关键要找到对应的ViewModelStore,而Fragment的ViewModelStore获取方式如下:
#Fragment.java
public ViewModelStore getViewModelStore() {
if (mFragmentManager == null) {
throw new IllegalStateException(“Can’t access ViewModels from detached fragment”);
}
return mFragmentManager.getViewModelStore(this);
}
#FragmentManagerViewModel.java
ViewModelStore getViewModelStore(@NonNull Fragment f) {
//mViewModelStores 是Map,key 是Fragment唯一标识符 value 为Fragment对应的ViewModelStore
ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
if (viewModelStore == null) {
//不存在则创建
viewModelStore = new ViewModelStore();
//放入map
mViewModelStores.put(f.mWho, viewModelStore);
}
return viewModelStore;
}
到此,流程就比较清晰了:
FragmentManagerViewModel里的mViewModelStores里存储着所有Fragment的ViewModelStore。也即是Fragment的ViewModel实际上是存储在FragmentManagerViewModel里的。
接着来整体捋一下Fragment的ViewModel是如何在重建时保持的。
显而易见,Fragment ViewModel实际上是间接依赖Activity ViewModeStore。
Fragment 关联的lifecycleScope
lifecycleScope 监听着Fragment生命周期,若是Fragment被销毁,则lifecycleScope也会被取消。
Fragment ViewModel关联的viewModelScope
viewModelScope 与ViewModel 生命周期保持一致,若是ViewModel被销毁(Fragment被销毁而非重建),则viewModelScope也会被取消。
5. DialogFragment(Dialog和Fragment的结晶)
DialogFragment 使用
普通的Dialog并没有生命周期,而不关联生命周期的Dialog处理异步请求比较麻烦,此时DialogFragment出现了。
class MyDialogFragment : DialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val tv = TextView(context).apply {
text = “hello world”
setTextColor(Color.RED)
textSize = 30f
}
return tv
}
}
显示DialogFragment:
MyDialogFragment().show(supportFragmentManager, “dd”)
我们只需要定义Fragment所绑定的布局,最终布局将会显示在Dialog里。
DialogFragment 原理
Dialog 显示Fragment绑定的布局
你也许比较好奇:之前添加的Fragment都是指定父布局,将Fragment所绑定的布局添加到父布局里,那此时的DialogFragment所指定的父布局在哪呢?
从show方法入手:
public void show(@NonNull FragmentManager manager, @Nullable String tag) {
//就是添加普通的Fragment流程
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit();
}
#FragmentTransaction.java
public FragmentTransaction add(@NonNull Fragment fragment, @Nullable String tag) {
//没有指定父布局
doAddOp(0, fragment, tag, OP_ADD);
return this;
}
与添加普通Fragment不同的是此时并没有指定Fragment的父布局。
Dialog会监听Fragment生命周期:
#DialogFragment.java
private Observer mObserver = new Observer() {
public void onChanged(LifecycleOwner lifecycleOwner) {
if (lifecycleOwner != null && mShowsDialog) {
//拿到Fragment绑定的View
View view = requireView();
if (mDialog != null) {
//将View添加到Dialog里
mDialog.setContentView(view);
}
}
}
};
当生命周期回调后拿到Fragment绑定的View添加到Dialog里。
如此一来,Fragment就完成了和Dialog的配合显示界面。
Dialog的创建时机
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
return super.onCreateDialog(savedInstanceState);
}
重写该方法可以自定义Dialog或是监听默认Dialog的创建。
值得注意的是:在onAttach()/onCreate()里是拿不到Dialog对象的,因为那时候还没有创建Dialog,它在onCreateView()之前创建的。
6. ViewPager2(Fragment与RecyclerView的结晶)
ViewPager2使用
除了DialogFragment,Fragment也与RecyclerView配合,形成了ViewPager2。
创建Adapter:
public class VPAdapter extends FragmentStateAdapter {
private List list = new ArrayList<>();
public VPAdapter(@NonNull FragmentActivity fragmentActivity, List list) {
super(fragmentActivity);
this.list = list;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return list.get(position);
}
@Override
public int getItemCount() {
return list.size();
}
}
ViewPager2绑定Adapter:
VPAdapter vpAdapter = new VPAdapter(this, list);
viewPager2.setAdapter(vpAdapter);
可以看出,使用起来很简洁,ViewPager2的显示依靠着Fragment。
ViewPager2原理
RecyclerView缓存
在此之前先简单介绍一下RecyclerView(简称RV)的缓存设计。
RV缓存的是什么呢?
缓存的是ViewHolder(简称VH),VH里持有待显示的子布局(View)。
RecyclerView里有个内部类:Recycler,里面有5个缓存变量,归为3种缓存,分别为:
一级缓存(默认2个+1个预拉取)、二级缓存、三级缓存(默认5个,区分itemType)。
当RecyclerView渲染布局显示item时,先分别从一、二、三级缓存寻找可用的VH,若没有找到则重新创建子布局及其所属的VH,最终渲染。
VH有两种状态:
- VH保持着当前的数据状态,此种状态下当VH复用时可直接使用,对应一级缓存。
- VH仅仅保持着View,没有绑定数据,此种状态下当VH复用时需要重新绑定数据,也就是走onBindViewHolder()方法,对应三级缓存。
二级缓存是暴露给调用者设置自定义缓存的,此处先忽略。
先看看一、三级缓存是如何填充数据的。
再看RV是如何从缓存取数据的:
RecyclerView与Fragment联动
核心代码在FragmentStateAdapter.java里。
RecyclerView关键动作与Fragment的联动:
本质上还是将Fragment的View添加到RV提前构造的ItemView内。
我们来梳理一下ViewPager2(简称VP2)的滑动场景。
- VP2展示第一个元素,实际展示的是RV的第一个元素,此时RV回调了onCreateViewHolder、onBindViewHolder等回调,Fragment也走了生命周期,最终Fragment绑定的View添加到了RV的子Item里
- 当滑动VP2到第二个元素(下标为1)时,RV的第一个元素被放到一级缓存,此时RV触发移除子Item,注意这个时候并没有销毁Fragment
- 当滑动VP2回到第一个元素时,RV仅仅只需要addView即可,不会触发Fragment生命周期
- 当滑动VP2到后面几个元素时,此时一级缓存已满,将放到三级缓存里,然后触发子Item的回收,这个时候会移除对应的Fragment,Frament走生命周期里的销毁流程
- RV的预取元素时,会走onCreateViewHolder、onBindViewHolder回调,但不会触发addView,也就是不会触发Fragment的生命周期
VP2的缓存
public void setOffscreenPageLimit(@OffscreenPageLimit int limit)
设置VP2左右缓存的数量,默认是没有缓存的,也不能将缓存设置为0,只能是>=1。
VP2的缓存和RV的缓存是什么关系呢?
假设VP2缓存limit=1,再来梳理一下ViewPager2(简称VP2)的滑动场景。
- VP2展示第一个元素,实际展示的是RV的第一个元素,此时RV回调了onCreateViewHolder、onBindViewHolder等回调,Fragment也走了生命周期,最终Fragment绑定的View添加到了RV的子Item里。与此同时,VP2继续渲染第二个元素,与第一个元素步骤一致
- 当VP2滑动到第二个元素时,由于之前已经渲染过,此时是直接展示(RV无需addView)。于此同时会继续提前缓存第三个元素。
- 当VP2滑动到第一个元素时,,由于之前已经渲染过,此时是直接展示。
可以看出VP2的缓存实际上是提前将RV的元素渲染了,若设置了limit=1,那么此时RV活跃的Item有三个:当前1个+左右各一个。
当设置了VP2的缓存后,意味着多缓存了Fragment实例。
以上是Fragment实际应用与原理的相关内容。
Android 学习笔录
**Android 性能优化篇:https://qr18.cn/FVlo89
Android Framework底层原理篇:https://qr18.cn/AQpN4J
Android 车载篇:https://qr18.cn/F05ZCM
Android 逆向安全学习笔记:https://qr18.cn/CQ5TcL
Android 音视频篇:https://qr18.cn/Ei3VPD
Jetpack全家桶篇(内含Compose):https://qr18.cn/A0gajp
OkHttp 源码解析笔记:https://qr18.cn/Cw0pBD
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数HarmonyOS鸿蒙开发工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年HarmonyOS鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新
如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
Cyk0-1712641949008)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新
如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
[外链图片转存中…(img-gMtwkGM8-1712641949009)]
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!