在使用友盟統計的時候常常會遇到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)
複製程式碼