Fragment懒加载(支持嵌套) 友盟统计Fragment时长最佳实践
来源:互联网 发布:mysql数据库用户名 编辑:程序博客网 时间:2024/06/05 05:44
前言
在项目中我们可能需要获取Fragment可见或者不可见时的回调。(回调这个词在这里用的可能并不准确,这里理解为当Fragment可见或者不可见时能够触发一些方法,下同)。
Fragmeng生命周期中有onResume
,onPause
,这两个生命周期是跟随Activity的。当调用getSupportFragmentManager().beginTransaction().hide(fragment)
时或者滑动ViewPager隐藏Fragment时,Fragment的这两个生命周期都不会回调。
那么,如何得到Fragment可见时的回调呢?如何得到Fragment不可见时的回调呢?
思路
首先先定义一个BetterLifecycleFragment继承自Fragment。我希望当Fragment可见状态改变时,子类可以有对应的生命周期的回调。如 onFragmentResume, onFragmentPause。如下:
public class BetterLifecycleFragment extends Fragment { /** * Fragment 可见时回调 * @param isFirst 是否是第一次显示 */ protected void onFragmentResume(boolean isFirst){ } /** * Fragment 不可见时回调 */ protected void onFragmentPause(){ }}
注意到这里 onFragmentResume 里有一个 isFirst参数,这个参数是为了方便懒加载。如果是第一次,则去请求数据。
统计Fragment时长也很简单,把原来onResume和onPause中的方法搬到这两个方法里即可。
判断Fragment可见的充分条件
我们先思考Fragment不可见都有几种情况:
1. Activity 进入后台,Fragment#onPause回调。
2. ViewPager中被滑出屏幕之外的Fragment
我们可以通过 getUserVisibleHint()
方法判断Fragment是否在屏幕之中。
3. Activity执行getSupportFragmentManager().beginTransaction().hide(fragment)
的Fragment。
这时 Fragment#onHiddenChanged(boolean hidden)
方法会执行。
除去上面三种情况,Fragment对于用户就是可见的了。
我们在 BetterLifecycleFragment中添加isFragmentVisible()
方法用来判断Fragment是否可见。
public class BetterLifecycleFragment extends Fragment { private boolean isResuming = false; private boolean hidden = false; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); hidden = false; } @Override public void onResume() { super.onResume(); isResuming = true; } @Override public void onPause() { super.onPause(); isResuming = false; } @Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); this.hidden = hidden; } /** * Fragment是否可见 * @return */ public boolean isFragmentVisible() { if (isResuming() && getUserVisibleHint() && !hidden) { return true; } return false; } /** * Fragment 是否在前台。 * @return */ private boolean isResuming() { return isResuming; }}
注意这里我们并没有使用系统的 isResumed()以及isHiddlen();
为什么呢?不妨自己在onPause以及onHiddenChanged(boolean hidden)
里面打印一下这两个方法就知道了。
完整实现
上述已经说过,Fragment不可见有三种情况。同理Fragment可见也和这三种情况有关。
Fragment可见状态改变的三种情况:
1. Fragment进入前台或者进入后台:
对应 onResume 和 onPause
2. ViewPager 滑动:
Fragment 的setUserVisibleHint(boolean isVisibleToUser)
触发。(事实上这个方法根本不会改变Fragment是否可见,只是告诉我们Fragment是否在屏幕之中。)
3. FragmentManager
调用了show或者hide:
Fragment 的onHiddenChanged(boolean hidden)
触发。
我们只需在Fragment中可能改变其可见状态的方法中调用我们的 isFragmentVisible()
,然后和上次Fragment的可见状态做个比较,即可得到Fragment可见以及不可见的回调。
完整代码如下:
public class BetterLifecycleFragment extends Fragment { private boolean isLastVisible = false; private boolean hidden = false; private boolean isFirst = true; private boolean isResuming = false; private boolean isViewDestroyed = false; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); isLastVisible = false; hidden = false; isFirst = true; isViewDestroyed = false; } @Override public void onResume() { super.onResume(); isResuming = true; tryToChangeVisibility(true); } @Override public void onPause() { super.onPause(); isResuming = false; tryToChangeVisibility(false); } @Override public void onDestroyView() { super.onDestroyView(); isViewDestroyed = true; } @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); setUserVisibleHintClient(isVisibleToUser); } private void setUserVisibleHintClient(boolean isVisibleToUser) { tryToChangeVisibility(isVisibleToUser); if (isAdded()) { // 当Fragment不可见时,其子Fragment也是不可见的。因此要通知子Fragment当前可见状态改变了。 List<Fragment> fragments = getChildFragmentManager().getFragments(); if (fragments != null) { for (Fragment fragment : fragments) { if (fragment instanceof BetterLifecycleFragment) { ((BetterLifecycleFragment) fragment).setUserVisibleHintClient(isVisibleToUser); } } } } } @Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); onHiddenChangedClient(hidden); } public void onHiddenChangedClient(boolean hidden) { this.hidden = hidden; tryToChangeVisibility(!hidden); if (isAdded()) { List<Fragment> fragments = getChildFragmentManager().getFragments(); if (fragments != null) { for (Fragment fragment : fragments) { if (fragment instanceof BetterLifecycleFragment) { ((BetterLifecycleFragment) fragment).onHiddenChangedClient(hidden); } } } } } private void tryToChangeVisibility(boolean tryToShow) { // 上次可见 if (isLastVisible) { if (tryToShow) { return; } if (!isFragmentVisible()) { onFragmentPause(); isLastVisible = false; } // 上次不可见 } else { boolean tryToHide = !tryToShow; if (tryToHide) { return; } if (isFragmentVisible()) { onFragmentResume(isFirst, isViewDestroyed); isLastVisible = true; isFirst = false; } } } /** * Fragment是否可见 * * @return */ public boolean isFragmentVisible() { if (isResuming() && getUserVisibleHint() && !hidden) { return true; } return false; } /** * Fragment 是否在前台。 * * @return */ private boolean isResuming() { return isResuming; } /** * Fragment 可见时回调 * * @param isFirst 是否是第一次显示 * @param isViewDestroyed Fragment中的View是否被回收过。 * 存在这种情况:Fragment 的 View 被回收,但是Fragment实例仍在。 */ protected void onFragmentResume(boolean isFirst, boolean isViewDestroyed) { } /** * Fragment 不可见时回调 */ protected void onFragmentPause() { }}
值得注意:
1. 如果Fragment存在嵌套,那么父Fragment的可见状态将影响到子Fragment的可见状态。所以父Fragment在可见状态改变时要通知子Fragment可见状态发生改变了。
2. 考虑一种情况,Fragment的View被回收,但是Fragment实例仍在,这种在ViewPager中是存在的。所以在onFragmentResume方法中我加入了一个isViewDestroyed表示Fragment的View是否被收回过。
懒加载实现如下:
@Overrideprotected void onFragmentResume(boolean isFirst, boolean isViewDestroy) { if(isFirst){ loadData(); } else if(isViewDestroy){ // 为View设置数据。当然也可以在onCreateView或者onActivityCreate中设置数据。 setViews(); }}
友盟统计Fragment时长只需把原来onResume和onPuase中的方法copy到onFragmentResume及onFragmentPause方法中即可。
点我下载源码
- Fragment懒加载(支持嵌套) 友盟统计Fragment时长最佳实践
- viewpager嵌套Fragment懒加载
- Fragment嵌套Fragment,Viewpager和Fragment联动,懒加载
- 记录ViewPage+Fragment嵌套ViewPage+Fragment滑动时内部嵌套卡顿的问题和实现Fragment的懒加载
- ViewPager+Fagment 嵌套 Fragment懒加载
- Fragment懒加载 可实现嵌套
- ActionBar Fragment运用最佳实践
- ActionBar Fragment运用最佳实践
- tab+Fragment管理最佳实践
- GridView+Fragment+ViewPager最佳实践
- Fragment双层嵌套时,
- fragment嵌套fragment,支持点击、滑动变换页面效果
- Fragment 嵌套Fragment时,用getChildFragmentManager()
- Fragment嵌套Fragment
- fragment 嵌套fragment
- Fragment 嵌套Fragment注意事项
- Fragment 嵌套 Fragment 问题
- Fragment中嵌套Fragment
- Max Consecutive Ones
- 这三种研发工程师千万不能招?
- Tomcat整体框架总结
- android xml文件中透明效果设置
- Mybatis思维导图
- Fragment懒加载(支持嵌套) 友盟统计Fragment时长最佳实践
- Error:Execution failed for task ':app:processDebugManifest'. > Manifest merger failed with multiple
- 第六章.for循环结构
- HDU 1506 Largest Rectangle in a Histogram(DP)
- [树形DP] BZOJ 4033 [HAOI2015]树上染色
- linux下QT+MYSQL开发
- EDAS系统投稿
- linux上anaconda的卸载
- Java关键字final的理解