ViewPagerで動的にFragmentを交換してリフレッシュしない問題

3607 ワード

ViewPager+Fragmentを使用してインタフェースを構築する際、ViewPagerの最初のitemにButtonがあり、Buttonをクリックすると最初のitemのFragmentを別のFragmentに置き換えるというニーズに遭遇しました.前に考えていたのは、adapterのリストのデータを交換し、notifyDataSetChangedで無効であることを発見しました.FragmentPagerAdapterのソースコードの発見を研究し、
@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をキャッシュすることなく、毎回再構築を破棄し、効率が低く、ページへのアクセスが非常に少ないなどの特殊な状況に適しています.