這個情況僅適合與多個fragment之間切換時統計,而非activity和fragment同時互動,因當時專案為首頁4個fargment時長統計,因此適合,經下面網友評論指出,特在這裡寫出此問題,因最近專案較忙,具體情況以後驗證後會發出博文更新。
現在越來越多的應用會使用viewpager+fragment顯示自己的內容頁,fragment和activity有很多共同點,如下圖就是fragment的生命週期
但是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(); } }
這個 DEFAULT_OFFSCREEN_PAGES 定義如下 private static final intDEFAULT_OFFSCREEN_PAGES= 1;
就是如果你設定為0 也沒用。!!!
為了解決判斷是否fragment當前顯示問題 可以在fragment重寫 setUserVisibleHint(boolean isVisibleToUser)
在fragment新增log日誌
public class Fragment1 extends Fragment { private static final String TAG = "Fragment1"; @Override public void onAttach(Activity activity) { super.onAttach(activity); L.v(TAG, "onAttach"); } @Override public void setUserVisibleHint(boolean isVisibleToUser) { L.v(TAG, "setUserVisibleHint " + isVisibleToUser); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); L.v(TAG, "onCreate"); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { L.v(TAG, "onCreateView"); View view = inflater.inflate(R.layout.fragment_layout,null); TextView tv = (TextView) view.findViewById(R.id.tv1); tv.setText(TAG); return view; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); L.v(TAG,"onActivityCreated"); } @Override public void onResume() { super.onResume(); L.v(TAG, "onResume()"); } @Override public void onPause() { super.onPause(); L.v(TAG,"onPause"); } @Override public void onStop() { super.onStop(); L.v(TAG,"onStop"); }
啟動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時可以執行一下程式碼
@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
可見這樣就可以準確統計使用者是否離開或者開始瀏覽介面了。根據這些開始和離開可以統計使用者停留介面的時間等資料。