1. 程式人生 > >這才是FragmentPagerAdapter重新整理fragment最完美解決方案

這才是FragmentPagerAdapter重新整理fragment最完美解決方案

看了網上解決 FragmentPagerAdapter重新整理問題是主要是使用 FragmentPagerAdapter強制重新整理。解決方案是這樣的:

public void setFragments(ArrayList fragments) {
if(this.fragments != null){
FragmentTransaction ft = fm.beginTransaction();
for(Fragment f:this.fragments){
ft.remove(f);
}
ft.commit();
ft=null;
fm.executePendingTransactions();
}
this.fragments = fragments;
notifyDataSetChanged();
}

這種方案存在的問題:
(1)重複建立大量新的fragment,開銷比較大。
(2)fm.executePendingTransactions()這句程式碼會導致谷歌的一個重大的崩潰bug:
‘android.os.Handler android.support.v4.app.FragmentHostCallback.getHandler()’ on a null object reference
這個bug雖然在stackoverflow上給出路解決方案:
解決連結
但是我試了,然並軟,果斷放棄上面的方案,尋找新的出路。
重點來了
在FrammentPagerAdapter的instantiateItem方法中:

public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG) Log.v(TAG, “Attaching item #” + itemId + “: f=” + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
if (DEBUG) Log.v(TAG, “Adding item #” + itemId + “: f=” + fragment);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}

我們發現每次建立fragment時候,FragmentManager都會通過findFragmentByTag去快取中查詢,是否存在指定tagName的Fragment,有就複用,沒有就呼叫getItem()建立新的。而這裡的tagName就是通過getItemId()方法生成的。

原來FragmentPagerAdapter裡在根據getItemId(int position)來判斷當前position裡Fragment是否存在,如果存在,則不會建立亦不會更新,那麼要讓FragmentPagerAdapter的更新生效,那在getItemId(int)里根據資料返回一個唯一的資料ID,當FragmentPagerAdapter更新時,資料ID改變了,那麼Fragment就會呼叫getItem(int)去獲取新Fragment,達到更新效果
好了,我們的解決方案就是通過重新getItemId()方法,返回唯一的id。

@Override
public long getItemId(int position) {
return mTabItemIds.get(position).hashCode();
}

這裡的mTabItemIds我是使用的每個tab的id集合。然後返回不同tabId的hashcode作為唯一id。
同時還要重寫getItemPosition()方法,通知重新整理位置變化了。

@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}