ViewPagerで動的にFragmentを交換してリフレッシュしない問題
3607 ワード
ViewPager+Fragmentを使用してインタフェースを構築する際、ViewPagerの最初のitemにButtonがあり、Buttonをクリックすると最初のitemのFragmentを別のFragmentに置き換えるというニーズに遭遇しました.前に考えていたのは、adapterのリストのデータを交換し、notifyDataSetChangedで無効であることを発見しました.FragmentPagerAdapterのソースコードの発見を研究し、
それはinstantiateItemメソッドではリストに直接行ってFragmentを手に入れるのではなく、まずFragmentManagerからTagを通じて対応するFragmentを探し、見つけられるならリストに入れないので、リストをいくら更新しても無駄で、解決策は以下の通りです.
1.instantiateItemメソッドを書き換える場合、FragmentManagerから更新が必要なFragmentを手動で削除します.コードは以下の通りです.
私がここで動的に交換するのは最初のitemのfragmentなので、if(position==0)を直接判断し、他の状況は必要に応じて修正することができます.まず、getFragmentTagメソッドを使用して、現在のpositionのfragmentのtagを取得します.このメソッドでは、FragmentPagerAdapterのmakeFragmentNameメソッドを反射的に呼び出します.ここでのtagは、このメソッドで計算されたものです.このコードは次のとおりです.
Tagが得られるとFragmentManagerのfindFragmentByTagメソッドでfragmentが得られ、存在する場合はFragmentTransactionで除去すればよい.
最後にgetItemPosition()メソッドを書き換え、POSITION_に戻るNONE.コードは次のとおりです.
2、FragmentStatePagerAdapterを使用すると、fragmentをキャッシュすることなく、毎回再構築を破棄し、効率が低く、ページへのアクセスが非常に少ないなどの特殊な状況に適しています.
@Override
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;
}
それはinstantiateItemメソッドではリストに直接行ってFragmentを手に入れるのではなく、まずFragmentManagerからTagを通じて対応するFragmentを探し、見つけられるならリストに入れないので、リストをいくら更新しても無駄で、解決策は以下の通りです.
1.instantiateItemメソッドを書き換える場合、FragmentManagerから更新が必要なFragmentを手動で削除します.コードは以下の通りです.
@Override
public Object instantiateItem(ViewGroup container, int position) {
// TODO Auto-generated method stub
if (position == 0)
removeFragment(container,position);
return super.instantiateItem(container, position);
}
private void removeFragment(ViewGroup container,int index) {
String tag = getFragmentTag(container.getId(), index);
Fragment fragment = fm.findFragmentByTag(tag);
if (fragment == null)
return;
FragmentTransaction ft = fm.beginTransaction();
ft.remove(fragment);
ft.commit();
ft = null;
fm.executePendingTransactions();
}
私がここで動的に交換するのは最初のitemのfragmentなので、if(position==0)を直接判断し、他の状況は必要に応じて修正することができます.まず、getFragmentTagメソッドを使用して、現在のpositionのfragmentのtagを取得します.このメソッドでは、FragmentPagerAdapterのmakeFragmentNameメソッドを反射的に呼び出します.ここでのtagは、このメソッドで計算されたものです.このコードは次のとおりです.
private String getFragmentTag(int viewId, int index) {
try {
Class cls = FragmentPagerAdapter.class;
Class>[] parameterTypes = { int.class, long.class };
Method method = cls.getDeclaredMethod("makeFragmentName",
parameterTypes);
method.setAccessible(true);
String tag = (String) method.invoke(this, viewId, index);
return tag;
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
Tagが得られるとFragmentManagerのfindFragmentByTagメソッドでfragmentが得られ、存在する場合はFragmentTransactionで除去すればよい.
最後にgetItemPosition()メソッドを書き換え、POSITION_に戻るNONE.コードは次のとおりです.
@Override
public int getItemPosition(Object object) {
// TODO Auto-generated method stub
return POSITION_NONE;
}
2、FragmentStatePagerAdapterを使用すると、fragmentをキャッシュすることなく、毎回再構築を破棄し、効率が低く、ページへのアクセスが非常に少ないなどの特殊な状況に適しています.