Android Fragment 要你何用?2,HarmonyOS鸿蒙屏幕适配和性能优化

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有两种状态:

  1. VH保持着当前的数据状态,此种状态下当VH复用时可直接使用,对应一级缓存。
  2. VH仅仅保持着View,没有绑定数据,此种状态下当VH复用时需要重新绑定数据,也就是走onBindViewHolder()方法,对应三级缓存。

二级缓存是暴露给调用者设置自定义缓存的,此处先忽略。
先看看一、三级缓存是如何填充数据的。

再看RV是如何从缓存取数据的:

RecyclerView与Fragment联动

核心代码在FragmentStateAdapter.java里。
RecyclerView关键动作与Fragment的联动:

本质上还是将Fragment的View添加到RV提前构造的ItemView内。

我们来梳理一下ViewPager2(简称VP2)的滑动场景。

  1. VP2展示第一个元素,实际展示的是RV的第一个元素,此时RV回调了onCreateViewHolder、onBindViewHolder等回调,Fragment也走了生命周期,最终Fragment绑定的View添加到了RV的子Item里
  2. 当滑动VP2到第二个元素(下标为1)时,RV的第一个元素被放到一级缓存,此时RV触发移除子Item,注意这个时候并没有销毁Fragment
  3. 当滑动VP2回到第一个元素时,RV仅仅只需要addView即可,不会触发Fragment生命周期
  4. 当滑动VP2到后面几个元素时,此时一级缓存已满,将放到三级缓存里,然后触发子Item的回收,这个时候会移除对应的Fragment,Frament走生命周期里的销毁流程
  5. RV的预取元素时,会走onCreateViewHolder、onBindViewHolder回调,但不会触发addView,也就是不会触发Fragment的生命周期
VP2的缓存

public void setOffscreenPageLimit(@OffscreenPageLimit int limit)

设置VP2左右缓存的数量,默认是没有缓存的,也不能将缓存设置为0,只能是>=1。

VP2的缓存和RV的缓存是什么关系呢?
假设VP2缓存limit=1,再来梳理一下ViewPager2(简称VP2)的滑动场景。

  1. VP2展示第一个元素,实际展示的是RV的第一个元素,此时RV回调了onCreateViewHolder、onBindViewHolder等回调,Fragment也走了生命周期,最终Fragment绑定的View添加到了RV的子Item里。与此同时,VP2继续渲染第二个元素,与第一个元素步骤一致
  2. 当VP2滑动到第二个元素时,由于之前已经渲染过,此时是直接展示(RV无需addView)。于此同时会继续提前缓存第三个元素。
  3. 当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鸿蒙开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

Cyk0-1712641949008)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上HarmonyOS鸿蒙开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注鸿蒙获取)
[外链图片转存中…(img-gMtwkGM8-1712641949009)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 16
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值