setUserVisibleHint的使用.執行順序和viewPager.setOffscreenPageLimit(0)不管用還是默認會加載第二個fragment


處理問題一:viewPager.setOffscreenPageLimit(0)不管用還是默認會加載第二個fragment的原因(源碼解讀);

處理問題二:setUserVisibleHint的使用場景和onCreate    onResume() 的執行順序

 

這個情況適合多個fragment之間切換時統計,而非activity和fragment同時交換,現在越來越多的應用會使用viewpager+fragment顯示自己的內容頁,fragment和activity有很多共同點。但是fragment和activity不同的是當調用本身的onResume和onPause方法的時候可能並不是當前的fragment在顯示,例如當加載下面這張圖時,當我打開MainActivity時顯示的是第一個fragment 但此時調用的方法步驟如下:

08-11 11:33:36.158    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onAttach
08-11 11:33:36.158    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onCreate
08-11 11:33:36.159    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onCreateView
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onActivityCreated
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onResume()
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onAttach
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onCreate
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onCreateView
08-11 11:33:36.161    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onActivityCreated

08-11 11:33:36.161    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onResume()  

可見此時雖然用戶看到的是第一個fragment 但第二個fragment onAttech onCreate   onCreateView onActivityCreater onStart(“這個我沒有打印log”)onResume 方法已經調用,這會導致如果我們要統計用戶更喜歡哪個fragment的內容時,雖然fragment已經創建並且onResume但其實並沒有顯示這一頁,那么是什么原因呢,這是因為Android v4包下的viewpager,為了讓用戶在切換過程中不會卡頓,谷歌官方默認當創建第一個fragment方法時回創建第二個fragment以確保用戶滑動時第二個view已經被創建,保持viewPager的平滑滑動效果

 

翻閱谷歌api發現viewpager有一個方法即 setOffscreenPageLimit。但當在viewpager設置以下代碼

 

viewPager.setOffscreenPageLimit(0);

 

運行時打印的log和上面完全一致,即就算你設置只加載一個fragment還是會加載第二個fragment,原因是setOffscreenPageLimit中的源碼時這樣寫的

public void setOffscreenPageLimit(int limit) {  
        if (limit < DEFAULT_OFFSCREEN_PAGES) {  
            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +  
                    DEFAULT_OFFSCREEN_PAGES);  
            limit = DEFAULT_OFFSCREEN_PAGES;  
        }  
        if (limit != mOffscreenPageLimit) {  
            mOffscreenPageLimit = limit;  
            populate();  
        }  
    }  

為了解決判斷是否fragment當前顯示問題 可以在fragment重寫 setUserVisibleHint(boolean isVisibleToUser)

啟動activity打印日志如下:

08-11 11:33:36.156    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint false
08-11 11:33:36.156    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ setUserVisibleHint false
08-11 11:33:36.157    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint true
08-11 11:33:36.158    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onAttach
08-11 11:33:36.158    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onCreate
08-11 11:33:36.159    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onCreateView
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onActivityCreated
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onResume()
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onAttach
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onCreate
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onCreateView
08-11 11:33:36.161    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onActivityCreated
08-11 11:33:36.161    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onResume()

當切換到第二個fragment時打印日志:

08-11 11:33:54.084    7162-7162/com.example.yinsgo.myui V/Fragment3﹕ setUserVisibleHint false
08-11 11:33:54.084    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint false
08-11 11:33:54.084    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ setUserVisibleHint true
08-11 11:33:54.084    7162-7162/com.example.yinsgo.myui V/Fragment3﹕ onAttach
08-11 11:33:54.085    7162-7162/com.example.yinsgo.myui V/Fragment3﹕ onCreate
08-11 11:33:54.085    7162-7162/com.example.yinsgo.myui V/Fragment3﹕ onCreateView
08-11 11:33:54.085    7162-7162/com.example.yinsgo.myui V/Fragment3﹕ onActivityCreated
08-11 11:33:54.085    7162-7162/com.example.yinsgo.myui V/Fragment3﹕ onResume()

可見當fragment顯示時回調用方法 setUserVisibleHint中的isVisibleToUser = true 當fragment被切換隱藏時回 isVisibleToUser = false;

所以當我們要統計是否用戶看到一個fragment時可以執行一下代碼

  1. @Override  
        public void setUserVisibleHint(boolean isVisibleToUser) {  
            L.v(TAG, "setUserVisibleHint " + isVisibleToUser);  
            if (isVisibleToUser) {  
                //統計代碼 或者 fragment顯示操作  
            } else {  
                  
            }  
        }  

今天又看了一下發現單純的執行上面的代碼是有問題的,因為如果我們在else中認為用戶是離開界面其實是不對的,因為根據啟動第一個Fragment的log日志

08-11 11:33:36.156    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint false
08-11 11:33:36.156    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ setUserVisibleHint false
08-11 11:33:36.157    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint true
08-11 11:33:36.158    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onAttach
08-11 11:33:36.158    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onCreate
08-11 11:33:36.159    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onCreateView
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onActivityCreated
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onResume()
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onAttach
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onCreate
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onCreateView
08-11 11:33:36.161    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onActivityCreated
08-11 11:33:36.161    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onResume()

第一次setUserVisibleHint 方法 isVisibleToUser 是false 但其實這個時候只是還未初始化,並不是用戶已經瀏覽界面准備離開,於是這里我們需要一個輔助標記變量具體代碼如下:

/** 
     * 判斷是否是初始化Fragment 
     */  
    private boolean hasStarted = false;  
    @Override  
    public void setUserVisibleHint(boolean isVisibleToUser) {  
        super.setUserVisibleHint(isVisibleToUser);  
        L.v(TAG, "setUserVisibleHint " + isVisibleToUser);  
        if (isVisibleToUser) {  
            hasStarted = true;  
            L.v(TAG,"開始界面");  
        } else {  
            if (hasStarted) {  
                hasStarted = false;  
                L.v(TAG,"結束界面");  
            }  
        }  
    }  

  

當我們啟動MainActivity時 Log打印如下:

08-13 17:55:45.850  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint false
08-13 17:55:45.850  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ setUserVisibleHint false
08-13 17:55:45.850  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onAttach
08-13 17:55:45.850  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onCreate
08-13 17:55:45.850  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint true
08-13 17:55:45.860  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ 開始界面
08-13 17:55:45.860  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onCreateView
08-13 17:55:45.870  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onActivityCreated
08-13 17:55:45.880  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onResume()
08-13 17:55:45.880  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ onAttach
08-13 17:55:45.880  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ onCreate
08-13 17:55:45.880  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ onCreateView
08-13 17:55:45.880  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ onActivityCreated
08-13 17:55:45.880  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ onResume()

切換到第二個fragment時,此時離開第一個fagment  log打印如下

08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ setUserVisibleHint false
08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint false
08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ 結束界面
08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ setUserVisibleHint true
08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ 開始界面
08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ onAttach
08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ onCreate
08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ onCreateView
08-13 17:57:04.320  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ onActivityCreated
08-13 17:57:04.320  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ onResume()

切換到第三個fragment時,此時離開第二個fragment log打印如下:

08-13 17:58:15.040  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ setUserVisibleHint false
08-13 17:58:15.040  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ 結束界面
08-13 17:58:15.040  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ setUserVisibleHint true
08-13 17:58:15.040  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ 開始界面
08-13 17:58:15.040  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onPause
08-13 17:58:15.040  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onStop

可見這樣就可以准確統計用戶是否離開或者開始瀏覽界面了。根據這些開始和離開可以統計用戶停留界面的時間等數據。

 總結:

viewPager.setOffscreenPageLimit(0)並沒有什么用,因為goole為了用戶更好的體驗,已經在我們加載第一個fragment的時候默認同時又加載了第二個fragment,從源碼中的設置可以看的出來。所以我們的這個設置不能起到任何作用;

setUserVisibleHint(頁面的顯示隱藏)的使用場景就是在framgment顯示隱藏的時候進行一些操作(比如網絡請求等),避免一個頁面用戶已經不可見了還在重復的加載數據,優化了性能。同時setUserVisibleHint在fragmnent的所有的生命周期之前調用,是最先執行的一個方法。所以我們應該在初始化的時候先進行一次網絡請求,避免只在setUserVisibleHint顯示的時候進行網絡請求造成第一次進入頁面的時候數據不加載的情況(因為剛進入一個頁面的時候,setUserVisibleHint開始不顯示,一會顯示的時候我們開始網絡請求,但是onCreateView()並沒有執行,此時頁面沒有任何數據)。

 

(剛進入頁面的時候生命周期的執行順序)

08-13 17:55:45.850  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint false          //setUserVisibleHint開始不顯示
08-13 17:55:45.850  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ setUserVisibleHint false            //setUserVisibleHint開始不顯示
08-13 17:55:45.850  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onAttach
08-13 17:55:45.850  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onCreate
08-13 17:55:45.850  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint true               //一會顯示的時候我們開始網絡請求,但是onCreateView()並沒有執行
08-13 17:55:45.860  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ 開始界面
08-13 17:55:45.860  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onCreateView                            //onCreateView開始顯示,記載布局                            


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM