【Android Fragment】友盟統計 Fragment 頁面顯示隱藏的完美解決方案

panpf發表於2019-04-15

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

相關文章