【Android】友盟统计Fragment页面显示隐藏的完美解决方案
在使用友盟统计的时候常常会遇到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