百度网盘怎么做网站,小红书关键词搜索量查询,凡科建站多少钱,电子商务型网站1 前言
上一章节【Android Framework系列】第14章 Fragment核心原理(AndroidX版本#xff09;我们学习了Fragment的核心原理#xff0c;本章节学习常用的FragmentViewPager以及FragmentViewPager2的相关使用和一些基本的源码分析。 2 FragmentViewPager
我们常用的两个Page…1 前言
上一章节【Android Framework系列】第14章 Fragment核心原理(AndroidX版本我们学习了Fragment的核心原理本章节学习常用的FragmentViewPager以及FragmentViewPager2的相关使用和一些基本的源码分析。 2 FragmentViewPager
我们常用的两个PagerAdapter的实现类也就是FragmentStatePagerAdapter和FragmentPagerAdapter今天我们就来学习一下它们的使用方法并进行对比。
2.1 FragmentPagerAdapter 和 FragmentStatePagerAdapter 的区别
1. fragments对象的处理 FragmentPagerAdapter范围外fragments会保存在内存中(detach)但是fragment对应的View会被销毁 FragmentStatePagerAdapter范围外fragments不会保存在内存中(remove)View也会被销毁。 2. 状态的处理 FragmentPagerAdapter范围外fragments对应的SavedState会保存 FragmentStatePagerAdapter只保存范围内fragments对应的SavedState。这个SavedState在Fragment的生命周期回调中供外部传参数和Activity类似。 3. 适用场景相同数量的fragmentsFragmentPagerAdapter内存较大但页面切换更友好FragmentStatePagerAdapter内存占用少页面切换稍差。
因此FragmentPagerAdapter适用于Fragment数量少的情况FragmentStatePagerAdapter适用于Fragment数量多的情况。
我们首先来看下FragmentPagerAdapter Overridepublic Object instantiateItem(ViewGroup container, int position) {if (mCurTransaction null) {mCurTransaction mFragmentManager.beginTransaction();}final long itemId getItemId(position);// Do we already have this fragment?//判断请求的Fragment是否已经被生成过String name makeFragmentName(container.getId(), itemId);Fragment fragment mFragmentManager.findFragmentByTag(name);if (fragment ! null) {if (DEBUG) Log.v(TAG, Attaching item # itemId : f fragment);// 当前缓存有则直接使用mCurTransaction.attach(fragment);} else {fragment getItem(position); //调用这个方法来生成新的Fragmentif (DEBUG) Log.v(TAG, Adding item # itemId : f fragment);// 将新生成的Fragment存储起来以便以后再次用到时直接attach()mCurTransaction.add(container.getId(), fragment,makeFragmentName(container.getId(), itemId)); }if (fragment ! mCurrentPrimaryItem) {fragment.setMenuVisibility(false);if (mBehavior BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);} else {fragment.setUserVisibleHint(false);}}return fragment;}Overridepublic void destroyItem(NonNull ViewGroup container, int position, NonNull Object object) {Fragment fragment (Fragment) object;if (mCurTransaction null) {mCurTransaction mFragmentManager.beginTransaction();}if (DEBUG) Log.v(TAG, Detaching item # getItemId(position) : f object v fragment.getView());mCurTransaction.detach(fragment);if (fragment.equals(mCurrentPrimaryItem)) {mCurrentPrimaryItem null;}}FragmentPagerAdapter的destroyItem方法中调用了detach()只是改变Fragment状态说明只有消除整个adapter时候才能将生成的Fragment都消除掉不然就会直接在内存中。
接下来我们对比FragmentStatePagerAdapter Overridepublic Object instantiateItem(NonNull ViewGroup container, int position) {// If we already have this item instantiated, there is nothing// to do. This can happen when we are restoring the entire pager// from its saved state, where the fragment manager has already// taken care of restoring the fragments we previously had instantiated.// mFragments中对应位置有Fragment的情况下直接返回if (mFragments.size() position) {Fragment f mFragments.get(position);if (f ! null) {return f;}}if (mCurTransaction null) {mCurTransaction mFragmentManager.beginTransaction();}Fragment fragment getItem(position);if (DEBUG) Log.v(TAG, Adding item # position : f fragment);if (mSavedState.size() position) {Fragment.SavedState fss mSavedState.get(position);if (fss ! null) {fragment.setInitialSavedState(fss);}}while (mFragments.size() position) {mFragments.add(null);}fragment.setMenuVisibility(false);if (mBehavior BEHAVIOR_SET_USER_VISIBLE_HINT) {fragment.setUserVisibleHint(false);}mFragments.set(position, fragment);mCurTransaction.add(container.getId(), fragment);if (mBehavior BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);}return fragment;}Overridepublic void destroyItem(NonNull ViewGroup container, int position, NonNull Object object) {Fragment fragment (Fragment) object;if (mCurTransaction null) {mCurTransaction mFragmentManager.beginTransaction();}if (DEBUG) Log.v(TAG, Removing item # position : f object v ((Fragment)object).getView());while (mSavedState.size() position) {mSavedState.add(null);}mSavedState.set(position, fragment.isAdded()? mFragmentManager.saveFragmentInstanceState(fragment) : null);mFragments.set(position, null);// 缓存中移除fragment下次使用得重新创建mCurTransaction.remove(fragment);if (fragment.equals(mCurrentPrimaryItem)) {mCurrentPrimaryItem null;}}FragmentStatePagerAdapter在destroyItem方法调用的时候把Fragment移除了因此下次使用需要重新创建Fragment
3 FragmentViewPager2
ViewPager2是Android Jetpack库中的一个组件是用于在应用程序中实现页面切换和滑动效果的容器。其实ViewPager2本身继承自RecyclerView。可以复习下我们的【Android Framework系列】第12章 RecycleView相关原理及四级缓存策略分析
3.1 ViewPager2的作用和用途
3.1.1 ViewPager2使用场景
是一个功能强大的滑动容器可以应用于多种场景中提供了灵活的页面切换和布局定制功能使得应用程序界面更加丰富和交互性强可以用于以下场景 实现引导页或欢迎页 ViewPager2可以用于创建引导页或欢迎页让用户通过滑动浏览介绍应用程序功能或展示欢迎内容。 创建图片浏览器 ViewPager2可以用于创建图片浏览器允许用户通过滑动来切换不同的图片并支持缩放和手势交互。 构建轮播图 ViewPager2非常适合构建轮播图功能可以通过适配器动态加载不同的轮播项并提供自动循环滚动的功能。 实现选项卡式布局 结合TabLayoutViewPager2可以用于创建选项卡式布局让用户通过滑动选项卡来切换不同的内容页面。 创建垂直滑动页面 与ViewPager不同ViewPager2支持垂直方向的滑动因此可以用于创建垂直滑动的页面布局例如垂直滑动的导航菜单或垂直的新闻列表。 实现分页数据展示 ViewPager2可以用于展示分页数据例如将大量数据按页加载并在每一页中展示一部分内容。 嵌套滑动布局 ViewPager2可以与其他滑动组件如RecyclerView嵌套使用实现复杂的滑动布局结构。 实现自定义的滑动效果 通过使用自定义的转换器Transformer可以实现各种炫酷的页面切换效果例如渐变、缩放、旋转等。
3.1.2 ViewPager2相较于ViewPager的改进和优势
ViewPager2是对ViewPager的改进版本提供了更好的性能、更灵活的适配器和更丰富的功能。它是构建滑动页面布局的首选组件可以在应用程序中实现各种滑动页面的需求并提供更好的用户体验大致有以下几点改进和优势 支持垂直滑动 ViewPager2是在ViewPager的基础上进行改进的最显著的改进之一是支持垂直滑动。而在ViewPager中只支持水平滑动。这使得ViewPager2在创建垂直布局或特定场景下的垂直滑动功能更加方便和灵活。 更好的性能和稳定性 ViewPager2内部实现使用了RecyclerView作为容器而不再依赖于ViewPager的实现方式。这使得ViewPager2具有RecyclerView的优势例如更好的性能和内存管理、更流畅的滑动体验以及更好的布局回收和复用机制。同时ViewPager2还解决了ViewPager一些已知的问题和不稳定性如条目位置错乱、刷新数据的不及时等。 支持使用Fragment作为页面 与ViewPager不同ViewPager2直接支持使用Fragment作为页面而无需通过FragmentPagerAdapter或FragmentStatePagerAdapter进行适配。这简化了页面管理和生命周期处理并提供了更直观和一致的使用体验。 更灵活的适配器 ViewPager2引入了新的适配器接口即RecyclerView.Adapter的子类RecyclerView.Adapter。这使得适配器的创建和管理更加灵活同时提供了更多的功能和扩展性。 更丰富的功能和接口 ViewPager2提供了许多新的功能和接口例如支持页面预加载、更强大的页面切换动画支持、更丰富的回调接口等。这些功能和接口使得开发者能够更好地控制和定制ViewPager2的行为和外观。
3.2 FragmentStateAdapter
上面我们了解了ViewPager2对比ViewPager的一些区别和优化点下面我们继续看一下ViewPager2对应的Adapter。 我们知道ViewPager2继承自RecyclerView那么它所对应的FragmentStateAdapter必定继承自RecyclerView.Adapter这点小伙伴们应该能理解。那么我们在RecyclerView中的每个Item加入Fragment作为容器展示。 RecyclerView.Adapter关注的是ViewHolder的复用但是在FragmentStateAdapter中的Framgent是不会复用的即有多少个item就应该创建多少个Fragment那么这其中是如何转换的呢
我们先来看看FragmentStateAdapter源码
public abstract class FragmentStateAdapter extendsRecyclerView.AdapterFragmentViewHolder implements StatefulAdapter {// 通过FragmentStateAdapter声明中的泛型可以知道// ViewPager2之所以能够在RecyclerView的基础上能对外屏蔽对ViewHolder的使用// 其内部是借助FragmentViewHolder实现的其内部就new了一个FrameLayout。Overridepublic final FragmentViewHolder onCreateViewHolder(NonNull ViewGroup parent, int viewType) {return FragmentViewHolder.create(parent);}Overridepublic final void onBindViewHolder(final NonNull FragmentViewHolder holder, int position) {final long itemId holder.getItemId();final int viewHolderId holder.getContainer().getId();final Long boundItemId itemForViewHolder(viewHolderId); // item currently bound to the VHif (boundItemId ! null boundItemId ! itemId) {removeFragment(boundItemId);mItemIdToViewHolder.remove(boundItemId);}mItemIdToViewHolder.put(itemId, viewHolderId); // this might overwrite an existing entry// 内部会最终回调到createFragment用来创建当前FragmentensureFragment(position);/** Special case when {link RecyclerView} decides to keep the {link container}* attached to the window, but not to the view hierarchy (i.e. parent is null) */final FrameLayout container holder.getContainer();if (ViewCompat.isAttachedToWindow(container)) {if (container.getParent() ! null) {throw new IllegalStateException(Design assumption violated.);}container.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {Overridepublic void onLayoutChange(View v, int left, int top, int right, int bottom,int oldLeft, int oldTop, int oldRight, int oldBottom) {if (container.getParent() ! null) {container.removeOnLayoutChangeListener(this);placeFragmentInViewHolder(holder);}}});}// 回收已经不在item集合中的Fragment节省内存开销gcFragments();}private void ensureFragment(int position) {long itemId getItemId(position);if (!mFragments.containsKey(itemId)) {// TODO(133419201): check if a Fragment provided here is a new FragmentFragment newFragment createFragment(position);newFragment.setInitialSavedState(mSavedStates.get(itemId));mFragments.put(itemId, newFragment);}}void gcFragments() {if (!mHasStaleFragments || shouldDelayFragmentTransactions()) {return;}// Remove Fragments for items that are no longer part of the data-setSetLong toRemove new ArraySet();for (int ix 0; ix mFragments.size(); ix) {long itemId mFragments.keyAt(ix);if (!containsItem(itemId)) {toRemove.add(itemId);mItemIdToViewHolder.remove(itemId); // in case theyre still bound}}// Remove Fragments that are not bound anywhere -- pending a grace periodif (!mIsInGracePeriod) {mHasStaleFragments false; // weve executed all GC checksfor (int ix 0; ix mFragments.size(); ix) {long itemId mFragments.keyAt(ix);if (!isFragmentViewBound(itemId)) {toRemove.add(itemId);}}}for (Long itemId : toRemove) {removeFragment(itemId);}}// onViewAttachToWindow的时候调用placeFragmentInViewHolder// 将FragmentViewHolder的container与当前Fragment绑定Overridepublic final void onViewAttachedToWindow(NonNull final FragmentViewHolder holder) {placeFragmentInViewHolder(holder);gcFragments();}void placeFragmentInViewHolder(NonNull final FragmentViewHolder holder) {Fragment fragment mFragments.get(holder.getItemId());if (fragment null) {throw new IllegalStateException(Design assumption violated.);}FrameLayout container holder.getContainer();View view fragment.getView();if (!fragment.isAdded() view ! null) {throw new IllegalStateException(Design assumption violated.);}// { f:added, v:notCreated, v:notAttached} - schedule callback for when createdif (fragment.isAdded() view null) {scheduleViewAttach(fragment, container);return;}// { f:added, v:created, v:attached } - check if attached to the right containerif (fragment.isAdded() view.getParent() ! null) {if (view.getParent() ! container) {addViewToContainer(view, container);}return;}// { f:added, v:created, v:notAttached} - attach view to containerif (fragment.isAdded()) {addViewToContainer(view, container);return;}// { f:notAdded, v:notCreated, v:notAttached } - add, create, attachif (!shouldDelayFragmentTransactions()) {scheduleViewAttach(fragment, container);mFragmentManager.beginTransaction().add(fragment, f holder.getItemId()).setMaxLifecycle(fragment, STARTED).commitNow();mFragmentMaxLifecycleEnforcer.updateFragmentMaxLifecycle(false);} else {if (mFragmentManager.isDestroyed()) {return; // nothing we can do}mLifecycle.addObserver(new LifecycleEventObserver() {Overridepublic void onStateChanged(NonNull LifecycleOwner source,NonNull Lifecycle.Event event) {if (shouldDelayFragmentTransactions()) {return;}source.getLifecycle().removeObserver(this);if (ViewCompat.isAttachedToWindow(holder.getContainer())) {placeFragmentInViewHolder(holder);}}});}}}public final class FragmentViewHolder extends ViewHolder {private FragmentViewHolder(NonNull FrameLayout container) {super(container);}// FragmentViewHolder实际上就创建了一个FrameLayoutNonNull static FragmentViewHolder create(NonNull ViewGroup parent) {FrameLayout container new FrameLayout(parent.getContext());container.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));container.setId(ViewCompat.generateViewId());container.setSaveEnabled(false);return new FragmentViewHolder(container);}NonNull FrameLayout getContainer() {return (FrameLayout) itemView;}
}
通过上面源码分析可以知道虽然Fragment没有被复用但是通过复用了ViewHolder的container实现了Framgent的交替显示
4 总结
总结一下本章节的内容
FragmentViewPager只能横向滚动性能相对较差。对应不同的Adapter效果不一样。FragmentViewPager使用FragmentPagerAdapter范围外fragments会保存在内存中(detach)但是fragment对应的View会被销毁fragments对应的SavedState会保存FragmentPagerAdapter内存较大但页面切换更友好适用于Fragment数量少的情况FragmentViewPager使用FragmentStatePagerAdapter范围外fragments不会保存在内存中(remove)View也会被销毁。只保存范围内fragments对应的SavedState。这个SavedState在Fragment的生命周期回调中供外部传参数和Activity类似。内存占用少页面切换稍差。适用于Fragment数量多的情况。FragmentViewPager2能横向或纵向滚动继承自RecyclerView所以基本有其所有的优点包括内存占用、缓存管理等。FragmentStateAdapter继承自RecyclerView.Adapter虽然Fragment没有被复用但是通过复用了ViewHolder的container实现了Framgent的交替显示。 文章转载自: http://www.morning.liyixun.com.gov.cn.liyixun.com http://www.morning.xdlwm.cn.gov.cn.xdlwm.cn http://www.morning.yzygj.cn.gov.cn.yzygj.cn http://www.morning.gqtxz.cn.gov.cn.gqtxz.cn http://www.morning.kdldx.cn.gov.cn.kdldx.cn http://www.morning.yrhsg.cn.gov.cn.yrhsg.cn http://www.morning.ssqrd.cn.gov.cn.ssqrd.cn http://www.morning.qlhwy.cn.gov.cn.qlhwy.cn http://www.morning.qhvah.cn.gov.cn.qhvah.cn http://www.morning.nxnrt.cn.gov.cn.nxnrt.cn http://www.morning.wlsrd.cn.gov.cn.wlsrd.cn http://www.morning.gmgnp.cn.gov.cn.gmgnp.cn http://www.morning.dpgdj.cn.gov.cn.dpgdj.cn http://www.morning.twmp.cn.gov.cn.twmp.cn http://www.morning.xwbwm.cn.gov.cn.xwbwm.cn http://www.morning.yybcx.cn.gov.cn.yybcx.cn http://www.morning.dhmll.cn.gov.cn.dhmll.cn http://www.morning.zzgkk.cn.gov.cn.zzgkk.cn http://www.morning.kpbgp.cn.gov.cn.kpbgp.cn http://www.morning.xirfr.cn.gov.cn.xirfr.cn http://www.morning.qmrsf.cn.gov.cn.qmrsf.cn http://www.morning.ysgnb.cn.gov.cn.ysgnb.cn http://www.morning.zzhqs.cn.gov.cn.zzhqs.cn http://www.morning.fpbj.cn.gov.cn.fpbj.cn http://www.morning.ftldl.cn.gov.cn.ftldl.cn http://www.morning.grwgw.cn.gov.cn.grwgw.cn http://www.morning.txqsm.cn.gov.cn.txqsm.cn http://www.morning.sgfpn.cn.gov.cn.sgfpn.cn http://www.morning.beeice.com.gov.cn.beeice.com http://www.morning.hffpy.cn.gov.cn.hffpy.cn http://www.morning.msgcj.cn.gov.cn.msgcj.cn http://www.morning.mfrb.cn.gov.cn.mfrb.cn http://www.morning.bmqls.cn.gov.cn.bmqls.cn http://www.morning.lmrcq.cn.gov.cn.lmrcq.cn http://www.morning.brbnc.cn.gov.cn.brbnc.cn http://www.morning.qhfdl.cn.gov.cn.qhfdl.cn http://www.morning.ffksr.cn.gov.cn.ffksr.cn http://www.morning.glrzr.cn.gov.cn.glrzr.cn http://www.morning.mbfj.cn.gov.cn.mbfj.cn http://www.morning.jjpk.cn.gov.cn.jjpk.cn http://www.morning.jqswf.cn.gov.cn.jqswf.cn http://www.morning.iuibhkd.cn.gov.cn.iuibhkd.cn http://www.morning.rszt.cn.gov.cn.rszt.cn http://www.morning.nlryq.cn.gov.cn.nlryq.cn http://www.morning.jxrpn.cn.gov.cn.jxrpn.cn http://www.morning.kwqcy.cn.gov.cn.kwqcy.cn http://www.morning.pwsnr.cn.gov.cn.pwsnr.cn http://www.morning.drbwh.cn.gov.cn.drbwh.cn http://www.morning.sgpnz.cn.gov.cn.sgpnz.cn http://www.morning.skrww.cn.gov.cn.skrww.cn http://www.morning.zbmcz.cn.gov.cn.zbmcz.cn http://www.morning.zpxwg.cn.gov.cn.zpxwg.cn http://www.morning.zqzzn.cn.gov.cn.zqzzn.cn http://www.morning.wkgyz.cn.gov.cn.wkgyz.cn http://www.morning.xcjwm.cn.gov.cn.xcjwm.cn http://www.morning.nktgj.cn.gov.cn.nktgj.cn http://www.morning.duqianw.com.gov.cn.duqianw.com http://www.morning.rzpkt.cn.gov.cn.rzpkt.cn http://www.morning.wcgcm.cn.gov.cn.wcgcm.cn http://www.morning.nlhcb.cn.gov.cn.nlhcb.cn http://www.morning.sypzg.cn.gov.cn.sypzg.cn http://www.morning.nzqmw.cn.gov.cn.nzqmw.cn http://www.morning.nldsd.cn.gov.cn.nldsd.cn http://www.morning.knswz.cn.gov.cn.knswz.cn http://www.morning.fnwny.cn.gov.cn.fnwny.cn http://www.morning.lgnz.cn.gov.cn.lgnz.cn http://www.morning.cqyhdy.cn.gov.cn.cqyhdy.cn http://www.morning.yqsr.cn.gov.cn.yqsr.cn http://www.morning.fcftj.cn.gov.cn.fcftj.cn http://www.morning.rlxnc.cn.gov.cn.rlxnc.cn http://www.morning.fxzw.cn.gov.cn.fxzw.cn http://www.morning.sgwr.cn.gov.cn.sgwr.cn http://www.morning.nrpp.cn.gov.cn.nrpp.cn http://www.morning.fksyq.cn.gov.cn.fksyq.cn http://www.morning.blxor.com.gov.cn.blxor.com http://www.morning.gwhjy.cn.gov.cn.gwhjy.cn http://www.morning.rgnq.cn.gov.cn.rgnq.cn http://www.morning.rkbly.cn.gov.cn.rkbly.cn http://www.morning.lgkbn.cn.gov.cn.lgkbn.cn http://www.morning.dbcw.cn.gov.cn.dbcw.cn