Android-- FragmentStatePagerAdapter分頁

來源:互聯網
上載者:User

標籤:

ViewPager

 

ViewPager 如其名所述,是負責翻頁的一個 View。準確說是一個 ViewGroup,包含多個 View 頁,在手指橫向滑動螢幕時,其負責對 View 進行切換。為了產生這些 View 頁,需要提供一個 PagerAdapter 來進行和資料繫結以及產生最終的 View 頁。
  • setAdapter()
    • ViewPager 通過 setAdapter() 來建立與 PagerAdapter 的聯絡。這個聯絡是雙向的,一方面,ViewPager 會擁有 PagerAdapter 對象,從而可以在需要時調用 PagerAdapter 的方法;另一方面,ViewPager 會在 setAdapter() 中調用 PagerAdapter 的 registerDataSetObserver() 方法,註冊一個自己產生的 PagerObserver 對象,從而在 PagerAdapter 有所需要時(如 notifyDataSetChanged() 或 notifyDataSetInvalidated() 時),可以調用 Observer 的 onChanged() 或 onInvalidated() 方法,從而實現 PagerAdapter 向 ViewPager 方向發送資訊。
  • dataSetChanged()
    • 在 PagerObserver.onChanged(),以及 PagerObserver.onInvalide() 中被調用。因此當 PagerAdapter.notifyDataSetChanged() 被觸發時,ViewPager.dataSetChanged() 也可以被觸發。該函數將使用 getItemPosition() 的傳回值來進行判斷,如果為 POSITION_UNCHANGED,則什麼都不做;如果為 POSITION_NONE,則調用 PagerAdapter.destroyItem() 來去掉該對象,並設定為需要重新整理 (needPopulate = true) 以便觸發 PagerAdapter.instantiateItem() 來產生新的對象。

 

PagerAdapter

PageAdapter 是 ViewPager 的支援者,ViewPager 將調用它來取得所需顯示的頁,而 PageAdapter 也會在資料變化時,通知 ViewPager。這個類也是FragmentPagerAdapter 以及 FragmentStatePagerAdapter 的基類。如果繼承自該類,至少需要實現 instantiateItem(), destroyItem(), getCount() 以及 isViewFromObject()。

 

  • getItemPosition()
    • 該函數用以返回給定對象的位置,給定對象是由 instantiateItem() 的傳回值。
    • 在 ViewPager.dataSetChanged() 中將對該函數的傳回值進行判斷,以決定是否最終觸發 PagerAdapter.instantiateItem() 函數。
    • 在 PagerAdapter 中的實現是直接傳回 POSITION_UNCHANGED。如果該函數不被重載,則會一直返回 POSITION_UNCHANGED,從而導致 ViewPager.dataSetChanged() 被調用時,認為不必觸發 PagerAdapter.instantiateItem()。很多人因為沒有重載該函數,而導致調用
       PagerAdapter.notifyDataSetChanged() 後,什麼都沒有發生。
  • instantiateItem()
    • 在每次 ViewPager 需要一個用以顯示的 Object 的時候,該函數都會被 ViewPager.addNewItem() 調用。
  • notifyDataSetChanged()
    • 在資料集發生變化的時候,一般 Activity 會調用 PagerAdapter.notifyDataSetChanged(),以通知 PagerAdapter,而 PagerAdapter 則會通知在自己這裡註冊過的所有 DataSetObserver。其中之一就是在 ViewPager.setAdapter() 中註冊過的 PageObserver。PageObserver 則進而調用 ViewPager.dataSetChanged(),從而導致 ViewPager 開始觸發更新其內含 View 的操作。

 

FragmentPagerAdapter

 

FragmentPagerAdapter 繼承自 PagerAdapter。相比通用的 PagerAdapter,該類更專註於每一頁均為 Fragment 的情況。如文檔所述, 該類內的每一個產生的 Fragment 都將儲存在記憶體之中,因此適用於那些相對靜態頁,數量也比較少的那種;如果需要處理有很多頁,並且資料動態性較大、佔用記憶體較多的情況,應該使用FragmentStatePagerAdapter。FragmentPagerAdapter 重載實現了幾個必須的函數,因此來自 PagerAdapter 的函數,我們只需要實現 getCount(),即可。且,由於 FragmentPagerAdapter.instantiateItem() 的實現中,調用了一個新增的虛函數 getItem(),因此,我們還至少需要實現一個 getItem()。因此,總體上來說,相對於繼承自 PagerAdapter,更方便一些。
  • getItem()
    • 該類中新增的一個虛函數。函數的目的為產生新的 Fragment 對象。重載該函數時需要注意這一點。在需要時,該函數將被 instantiateItem() 所調用。
    • 如果需要向 Fragment 對象傳遞相對靜態資料時,我們一般通過 Fragment.setArguments() 來進行,這部分代碼應當放到 getItem()。它們只會在新產生 Fragment 對象時執行一遍。
    • 如果需要在產生 Fragment 對象後,將資料集裡面一些動態資料傳遞給該 Fragment,那麼,這部分代碼不適合放到 getItem() 中。因為當資料集發生變化時,往往對應的 Fragment 已經產生,如果傳遞資料部分代碼放到了 getItem() 中,這部分代碼將不會被調用。這也是為什麼很多人發現調用 PagerAdapter.notifyDataSetChanged() 後,getItem() 沒有被調用的一個原因。
  • instantiateItem()
    • 函數中判斷一下要產生的 Fragment 是否已經產生過了,如果產生過了,就使用舊的,舊的將被 Fragment.attach();如果沒有,就調用 getItem() 產生一個新的,新的對象將被 FragmentTransation.add()。
    • FragmentPagerAdapter 會將所有產生的 Fragment 對象通過 FragmentManager 儲存起來備用,以後需要該 Fragment 時,都會從 FragmentManager 讀取,而不會再次調用 getItem() 方法
    • 如果需要在產生 Fragment 對象後,將資料集中的一些資料傳遞給該 Fragment,這部分代碼應該放到這個函數的重載裡。在我們繼承的子類中,重載該函數,並調用 FragmentPagerAdapter.instantiateItem() 取得該函數返回 Fragment 對象,然後,我們該 Fragment 對象中對應的方法,將資料傳遞過去,然後返回該對象。
    • 否則,如果將這部分傳遞資料的代碼放到 getItem()中,在 PagerAdapter.notifyDataSetChanged() 後,這部分資料設定代碼將不會被調用。
  • destroyItem()
    • 該函數被調用後,會對 Fragment 進行 FragmentTransaction.detach()。這裡不是 remove(),只是 detach(),因此 Fragment 還在 FragmentManager 管理中,Fragment 所佔用的資源不會被釋放。

 

FragmentStatePagerAdapter

 

FragmentStatePagerAdapter 和前面的 FragmentPagerAdapter 一樣,是繼承子 PagerAdapter。但是,和 FragmentPagerAdapter 不一樣的是,正如其類名中的 ‘State‘ 所表明的含義一樣,該 PagerAdapter 的實現將只保留當前頁面,當頁面離開視線後,就會被消除,釋放其資源;而在頁面需要顯示時,產生新的頁面(就像 ListView 的實現一樣)。這麼實現的好處就是當擁有大量的頁面時,不必在記憶體中佔用大量的記憶體。
  • getItem()
    • 一個該類中新增的虛函數。
    • 函數的目的為產生新的 Fragment 對象。
    • Fragment.setArguments() 這種只會在建立 Fragment 時執行一次的參數傳遞代碼,可以放在這裡。
    • 由於 FragmentStatePagerAdapter.instantiateItem() 在大多數情況下,都將調用 getItem() 來產生新的對象,因此如果在該函數中放置與資料集相關的 setter 代碼,基本上都可以在 instantiateItem() 被調用時執行,但這和設計意圖不符。畢竟還有部分可能是不會調用 getItem() 的。因此這部分代碼應該放到 instantiateItem() 中。
  • instantiateItem()
    • 除非碰到 FragmentManager 剛好從 SavedState 中恢複了對應的 Fragment 的情況外,該函數將會調用 getItem() 函數,產生新的 Fragment 對象。新的對象將被 FragmentTransaction.add()。
    • FragmentStatePagerAdapter 就是通過這種方式,每次都建立一個新的 Fragment,而在不用後就立刻釋放其資源,來達到節省記憶體佔用的目的的。
  • destroyItem()
    • 將 Fragment 移除,即調用 FragmentTransaction.remove(),並釋放其資源。

Android-- FragmentStatePagerAdapter分頁

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.