版權宣告:
本賬號釋出文章均來自公眾號,承香墨影(cxmyDev),版權歸承香墨影所有。
未經允許,不得轉載。
一、前言
相信每個上線的 App ,都有資料的統計需求,那麼不可避免的會碰到頁面統計,俗稱: PV。
PV : ( Page View ) ,即頁面瀏覽量或點選量,使用者每次對這個頁面的訪問均被記錄一次 PV。
那麼本文就聊聊如何準確的統計到頁面的 PV,其實如果是單個頁面的 PV ,比較單純一點會很好統計到,但是如果 ViewPager + Fragment 這種複雜組合的頁面,對單個 Fragment 的 PV 進行統計,就需要一些其他的方法了。
首先明確一下我對 PV 的定義,這個頁面,在使用者場景下,展示一次,就算一次PV,那麼涵蓋幾個點:
- 頁面第一次展示。
- 頁面進入其他頁面又回來。
- 在當前頁面退出到後臺再切回來。
- 在當前頁面鎖屏後解鎖再回來。
二、Activity 中直接使用 Fragment
有時候,為了方便移植,會以 Activity 內部巢狀一個 Fragment 的方式構成一個頁面,其實這樣結構的 PV ,非常的好統計到,只需要在其生命週期方法 onResume() 中,記錄一下頁面的統計點即可。這樣就不會有遺漏,其實也沒什麼好說的。
三、ViewPager 內的 Fragment
到本文的主題了。
雖然一個Activity 巢狀 一個 Fragment 的場景是有的,但是有一些時候,我們會使用一個 ViewPager + Fragment 的組合結構,來承載更多的業務,實際上多個Fragment 的業務互不關聯,對於關心資料的那幫人而言,它們應該算成獨立的 PV。
1、遇到的問題
如果和前面的場景一樣,在 Fragment.onResume() 中做頁面統計,就會發現一個很尷尬的問題,這個統計,不會準確,有些 Fragment 的 PV 會多。
因為 ViewPager 的特性,決定了它實際上是會快取前後兩個Fragment 的,加上自身,最多的時候是會快取三個,並且這個設定是無法修改的,我們沒有辦法將其修改只快取當前的一個。
可以看到,當設定的值小於 DEFAULT_OFFSCREEN_PAGES 的時候,就會又被設定為 DEFAULT_OFFSCREEN_PAGES ,這個值,就是 1 。
既然已經瞭解了這個特性,在使用 onResume() 來做統計,就會發生一個很尷尬的問題,第一個Fragment0 出現的時候,第二個 Fragment1 也會走生命週期方法 onCreate() → onResume() 。這樣可能使用者根本沒有進入第二個 Fragment1 ,但是卻被我們統計到了一次 PV。
所以這種情況下,使用 onResume() 來做 PV 的統計,是不靠譜的。
2、使用setUserVisibleHint
那麼如果需要統計到 ViewPager 中 Fragment 的真實 PV 資料的話,就需要使用到 setUserVisibleHint() 這個方法了。
setUserVisibleHint() 方法在 v4包和 原生app 包中的 Fragment 都是有這個方法的,功能也是一樣的,這裡就 v4 包下的看看原始碼的說明。
它會在這個 Fragment 被使用者可見或者隱藏的時候呼叫,正好就符合我們對 Fragment 承載的頁面 PV 統計的需要。
只需要重寫該方法,並在 isVisibleToUser 為 true 的時候,記錄一次該頁面的 PV 。
但是這樣,如果只是監聽 setUserVisibleHint() 方法,還是會有遺漏,在此頁面,如果切到後臺再回來,或者鎖屏再回來,都不會走到 setUserVisibleHint() 方法,所以還是需要配合 onResume() 來做 PV 的統計。
在 onResume() 的時候,通過 getUserVisibleHint() 拿到當前 Fragment 的顯示狀態,通過判斷來決定是否需要打 PV 的統計點,這裡就不細說了。
3、setUserVisibleHint 的原理
這樣是不是皆大歡喜,你以為這樣就完了嗎?
那麼這個方法在 Fragment 的生命週期方法中,並沒有被提到,它是如何被呼叫的?為什麼在 Activity 巢狀 Fragment 的場景下,不能使用它呢?
文件中其實已經說明了,它是一個宣告週期之外的方法,它可能被用在一組 Fragment 裡,如果對這一組 Fragment 的宣告週期需要更新,可以自行呼叫 setUserVisibleHint() 方法。
那麼,在我們這個場景下,setUserVisibleHint() 方法是在哪裡被呼叫的呢?
這就需要追溯到 FragmentPagerAdapter 類裡,在其中 instantiateItem() 和 setPrimaryItem() 方法,都有對其 Fragment 呼叫setUserVisibleHint() 方法,我們就 setPrimaryItem() 的原始碼看看它的實現。
可以看到,它會在切換 item 的時候,如果當前 item 不為空,就呼叫 setUserVisibleHint(false) ,標記當前 Fragmet 被隱藏掉了。而將新的 item 呼叫 setUserVisibleHint(true),標記當前 Fragment 被顯示了。
所以這裡才是,ViewPager 內,Fragment.setUserVisibleHint() 方法會被呼叫的關鍵。
FragmentPagerAdapter 和 FragmentStatePagerAdapter 中,都有類似的實現,只要我們沒閒的直接使用 PagerAdapter ,就不會有什麼問題。
四、結語
看了原始碼,做到心裡有底。統計的資料做不得馬虎,一定要精準才能反應出真實的情況。