【Android Fragment】友盟统计 Fragment 页面显示隐藏的完美解决方案

1,313 阅读3分钟

在使用友盟统计的时候常常会遇到Activity加Fragment的组合,统计起来比较麻烦。

友盟给出的解决方案是在Activity的onResume()和onPause()方法中执行MobclickAgent.onResume()加MobclickAgent.onPause()统计时长然后在Fragment的onResume()和onPause()方法中执行MobclickAgent.onPageStart()加MobclickAgent.onPageEnd()统计页面

默认情况下在MobclickAgent.onResume()和MobclickAgent.onPause()方法中会自动执行MobclickAgent.onPageStart()和MobclickAgent.onPageEnd()来统计页面,要想不自动统计页面只需在Application或程序入口处执行MobclickAgent.openActivityDurationTrack(false)即可

这个方案在普通的使用方式中没啥问题,但在ViewPager中却有很严重的BUG。

众所周知ViewPager会在初始化的时候一次性初始化2个Fragment,并且这两个Fragment都处于resume状态。但用户只能看到第一个Fragment,这时候你能说第二个Fragment也显示了吗?我们只能说第二个Fragment也准备好了,不能说显示了。这样带来的BUG就是明明第二个Fragment用户都没有看到,却统计成了已显示。

那么还有没有合适的回调方法能够帮助我们准确的统计Fragment呢?当然有。

Fragment有个叫setUserVisibleHint(boolean)的方法就是专门设置显示不显示的,ViewPager会在初始化Fragment的时候以及切换Fragment的时候调用此方法设置是否显示。那是不是只重写这个方法然后调用MobclickAgent.onPageStart()加MobclickAgent.onPageEnd()就可以了,经过验证后只能很遗憾的告诉你,不可以!

因为ViewPager会在设置Adapter之后立即调用第一个、第二个fragment的setUserVisibleHint(boolean)方法设置为false,然后会对第一个fragment再次调用setUserVisibleHint(boolean)方法设置为true,然后才是onAttach()、onCreate(),很明显顺序不对。 另外当Fragment不是在ViewPager中使用的时候压根就不会调用setUserVisibleHint(boolean)方法

那么最终我们还是要结合Fragment的setUserVisibleHint(boolean)、onResume()、onPause()这三个方法才能完美的统计,最终实现方式如下所示:

public class MyFragment extends Fragment {
    private String pageName;

    public MyFragment() {
        pageName = getClass().getSimpleName();
    }

    @Override
    public void onResume() {
        super.onResume();

        if(getUserVisibleHint()){
            onVisibilityChangedToUser(true, false);
        }
    }

    @Override
    public void onPause() {
        super.onPause();

        if(getUserVisibleHint()){
            onVisibilityChangedToUser(false, false);
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);

        if(isResumed()){
            onVisibilityChangedToUser(isVisibleToUser, true);
        }
    }

    /**
     * 当Fragment对用户的可见性发生了改变的时候就会回调此方法
     * @param isVisibleToUser true:用户能看见当前Fragment;false:用户看不见当前Fragment
     * @param isHappenedInSetUserVisibleHintMethod true:本次回调发生在setUserVisibleHintMethod方法里;false:发生在onResume或onPause方法里
     */
    public void onVisibilityChangedToUser(boolean isVisibleToUser, boolean isHappenedInSetUserVisibleHintMethod){
        if(isVisibleToUser){
            if(pageName != null){
                MobclickAgent.onPageStart(pageName);
                Log.i("UmengPageTrack", pageName + " - display - "+(isHappenedInSetUserVisibleHintMethod?"setUserVisibleHint":"onResume"));
            }
        }else{
            if(pageName != null){
                MobclickAgent.onPageEnd(pageName);
                Log.w("UmengPageTrack", pageName + " - hidden - "+(isHappenedInSetUserVisibleHintMethod?"setUserVisibleHint":"onPause"));
            }
        }
    }
}```

重点就是在setUserVisibleHint(boolean)中加上isResume()过滤,在onResume()和onPause()中加上getUserVisibleHint()过滤

有同学该担心了,你上面不是说在普通使用方式中setUserVisibleHint(boolean)压根就不会被调用,那么意味着getUserVisibleHint()一直都是false,最终onResume()和onPause()中的代码根本就不会执行了,这样普通使用方式就不行了啊。

我要告诉大家的是大家的是Fragment的源码中明确显示,getUserVisibleHint()方法返回的是mUserVisibleHint字段的值,而mUserVisibleHint字段默认值是true

如果你需要ViewPager嵌套ViewPager,那么你还会遇到Fragment的mUserVisibleHint属性不同步的问题,请查看下一篇文章来解决
下一篇:[【Android】解决ViewPager嵌套时Fragment的mUserVisibleHint属性不同步的问题](http://www.jianshu.com/p/e7449278e33d)