[AS3.0.1]关于ViewPager、FragmentPagerAdapter、Fragment源码研究

您所在的位置:网站首页 太阳系实时运行位置图片 [AS3.0.1]关于ViewPager、FragmentPagerAdapter、Fragment源码研究

[AS3.0.1]关于ViewPager、FragmentPagerAdapter、Fragment源码研究

2024-07-17 06:58:46| 来源: 网络整理| 查看: 265

前言

关于fragment的生命周期大家几乎都懂了。不过还是贴下图吧!这张图挺不错的比较直观。

fragment的恢复是从onDestroyView到onCreateView

然后我们使用ViewPager的时候都知道,他会自动加载下一个fragment,以达到流畅的滑动,但是也会因为数据过多或者不断的刷新页面导致应用卡顿等问题。

所以想要让fragment不提前加载,查了下百度,大部分方案有以下两个 1.将v4包内的ViewPager拷贝出来将private static final int DEFAULT_OFFSCREEN_PAGES = 1;改为0就可以实现单独加载一个fragment的效果。

2.通过fragment中的public void setUserVisibleHint(boolean isVisibleToUser)方法来进行判断是否展示了fragment从而选择是否加载数据。

原理探究

第二种方法让我决定看下ViewPager、FragmentPagerAdapter、Fragment三个之间的流程

log测试

首先我们创建一个TestFragment用来打印所以的生命周期log,看一下具体的日志

TestFragment.java

public class TestFragment extends Fragment { private View view; private String name = ""; public static TestFragment newInstance(String name) { TestFragment fragment = new TestFragment(); Bundle bundle = new Bundle(); bundle.putString("name", name); fragment.setArguments(bundle); return fragment; } @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); try { name = getArguments().getString("name", ""); } catch (Exception e) { e.printStackTrace(); } Log.e("-s-", "name = " + name); if (getUserVisibleHint()) { Log.e("-s-sssssss", name + "fragment is show."); } else { Log.e("-s-sssssss", name + "fragment is hide."); } } @Override public void onAttach(Context context) { super.onAttach(context); Log.e("-s-", name + "fragment is onAttach."); } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.e("-s-", name + "fragment is onCreate."); } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { if (view == null) { Log.e("-s-", name + "fragment is onCreateView."); view = inflater.inflate(R.layout.fragment_test, null); TextView tv = view.findViewById(R.id.tv_test_fm); tv.setText(name); } else { Log.e("-s-", name + "fragment is onCreateView ===> oldView"); } ViewGroup parent = (ViewGroup) view.getParent(); if (parent != null) { parent.removeView(view); } return view; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Log.e("-s-", name + "fragment is onActivityCreated."); } @Override public void onStart() { super.onStart(); Log.e("-s-", name + "fragment is onStart."); } @Override public void onResume() { super.onResume(); Log.e("-s-", name + "fragment is onResume."); } @Override public void onPause() { super.onPause(); Log.e("-s-", name + "fragment is onPause."); } @Override public void onStop() { super.onStop(); Log.e("-s-", name + "fragment is onStop."); } @Override public void onDestroyView() { Log.e("-s-", name + "fragment is onDestroyView."); super.onDestroyView(); } @Override public void onDestroy() { Log.e("-s-", name + "fragment is onDestroy."); super.onDestroy(); } @Override public void onDetach() { Log.e("-s-", name + "fragment is onDetach."); super.onDetach(); } }

Activity正常调用FragmentPagerAdapter和ViewPager 打开app初始如下log

E/-s-: name = first E/-s-sssssss: firstfragment is hide. E/-s-: name = second E/-s-sssssss: secondfragment is hide. E/-s-: name = first E/-s-sssssss: firstfragment is show. E/-s-: firstfragment is onAttach. E/-s-: firstfragment is onCreate. E/-s-: secondfragment is onAttach. E/-s-: secondfragment is onCreate. E/-s-: firstfragment is onCreateView. E/-s-: firstfragment is onActivityCreated. E/-s-: firstfragment is onStart. E/-s-: firstfragment is onResume. E/-s-: secondfragment is onCreateView. E/-s-: secondfragment is onActivityCreated. E/-s-: secondfragment is onStart. E/-s-: secondfragment is onResume.

发现开始最先被调用的方法其实是setUserVisibleHint而且确实创建了两个fragment,并且都执行到了onResume

之后我们滑动ViewPager将页面滑动到第二页,新log如下

E/-s-: name = third E/-s-sssssss: thirdfragment is hide. E/-s-: name = first E/-s-sssssss: firstfragment is hide. E/-s-: name = second E/-s-sssssss: secondfragment is show. E/-s-: thirdfragment is onAttach. E/-s-: thirdfragment is onCreate. E/-s-: thirdfragment is onCreateView. E/-s-: thirdfragment is onActivityCreated. E/-s-: thirdfragment is onStart. E/-s-: thirdfragment is onResume.

因为ViewPager的预加载将第三页也加载出来了,并且我们看到第一页被隐藏掉了。

在继续滑到第三页,log如下

E/-s-: name = four E/-s-sssssss: fourfragment is hide. E/-s-: name = second E/-s-sssssss: secondfragment is hide. E/-s-: name = third E/-s-sssssss: thirdfragment is show. E/-s-: fourfragment is onAttach. E/-s-: fourfragment is onCreate. E/-s-: firstfragment is onPause. E/-s-: firstfragment is onStop. E/-s-: firstfragment is onDestroyView. E/-s-: fourfragment is onCreateView. E/-s-: fourfragment is onActivityCreated. E/-s-: fourfragment is onStart. E/-s-: fourfragment is onResume.

由于默认的ViewPager设置的setOffscreenPageLimit是1所以目前页面加载到是第三页,保存的fragment有第二页(被隐藏)第三页(正在显示)第四页(预加载,被隐藏),而第一页就被关闭掉了。

最后再将第三页滑动回第二页,log如下

E/-s-: name = first E/-s-sssssss: firstfragment is hide. E/-s-: name = third E/-s-sssssss: thirdfragment is hide. E/-s-: name = second E/-s-sssssss: secondfragment is show. E/-s-: firstfragment is onCreateView ===> oldView E/-s-: firstfragment is onActivityCreated. E/-s-: fourfragment is onPause. E/-s-: fourfragment is onStop. E/-s-: fourfragment is onDestroyView. E/-s-: firstfragment is onStart. E/-s-: firstfragment is onResume.

至此我得到如下结论

1. ViewPager必定会预加载左右两边的fragment

2. 当出现过的fragment多于设置的setOffscreenPageLimit数量就会将除了预加载和前一页的fragment释放掉

源码排查

关于上面的log之后我们就可以看下源码方法的调用情况

首先先点击setUserVisibleHint看下调用的情况

很直观的可以看到在FragmentPagerAdapter中有3次调用,进到调用的地方看下源码 主要在两个方法中设置的fragment的是否显示instantiateItem和setPrimaryItem 以下是源码

@SuppressWarnings("ReferenceEquality") @Override public Object instantiateItem(ViewGroup container, int position) { if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } final long itemId = getItemId(position); // Do we already have this 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); if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment); mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), itemId)); } if (fragment != mCurrentPrimaryItem) { fragment.setMenuVisibility(false); fragment.setUserVisibleHint(false); } return fragment; } @SuppressWarnings("ReferenceEquality") @Override public void setPrimaryItem(ViewGroup container, int position, Object object) { Fragment fragment = (Fragment)object; if (fragment != mCurrentPrimaryItem) { if (mCurrentPrimaryItem != null) { mCurrentPrimaryItem.setMenuVisibility(false); mCurrentPrimaryItem.setUserVisibleHint(false); } if (fragment != null) { fragment.setMenuVisibility(true); fragment.setUserVisibleHint(true); } mCurrentPrimaryItem = fragment; } }

第一个instantiateItem很明显我们知道是Adapter添加fragment的代码 而后面一个setPrimaryItem设置属性的方法可以看出来是用于判断,当前页面的fragment是否是ViewPager滑动到的fragment,我们在看下setPrimaryItem的调用

可以看到就在ViewPager中Adapter使用了一次是在populate方法内,看方法名,我们可以知道这个ViewPager在填充fragment的方法。

至此我们就可以知道setUserVisibleHint的具体逻辑了。

首先先向FragmentPagerAdapter中加入多个fragment对象

ViewPager通过setOffscreenPageLimit中的值来确认需要填充的fragment数量,即调用populate方法

populate方法先确认需要添加的个数让Adapter调用instantiateItem方法加入fragment

最后让Adapter调用setPrimaryItem方法来设置fragment的setUserVisibleHint属性

这样就有了我们一开始看到的log

开始需要预加载1个fragment就调用了2次instantiateItem,然后再设置setPrimaryItem来设置显示与否。

之后滑到第二页是调用了1次instantiateItem,然后设置setPrimaryItem这个时候有第一页和第二页,所以设置第一页隐藏,第二页显示。

总结

通过逻辑我们可以知道为什么可以在setUserVisibleHint方法中来控制是否加载fragment网络数据,即百度到的fragment懒加载。 本篇就算是一段记录吧!

资料

Fragment的setUserVisibleHint详解



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


    图片新闻

    实验室药品柜的特性有哪些
    实验室药品柜是实验室家具的重要组成部分之一,主要
    小学科学实验中有哪些教学
    计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
    实验室各种仪器原理动图讲
    1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
    高中化学常见仪器及实验装
    1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
    微生物操作主要设备和器具
    今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
    浅谈通风柜使用基本常识
     众所周知,通风柜功能中最主要的就是排气功能。在

    专题文章

      CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭