web-dev-qa-db-ja.com

アクティビティの再開時にFragmentStatePagerAdapterの画像を更新します

FragmentStatePagerAdapterを使用して小さなギャラリーを提供するアクティビティを作成しました。ただし、アクティビティが再開したときに(他のアクティビティから戻った後など)、更新を取得できません。最初の2枚の画像が空白になるたびに、2枚の画像を横にスワイプした後にのみ、画像が更新されます。私が見つけた答えはどれも動作しません(特にgetItemPosition()をオーバーライドする)

私はそれを次のように設定しました:

_mPagerAdapter = new PhotosPagerAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.photosViewPager);
mPager.setAdapter(mPagerAdapter);
_

次に、FragmentStatePagerAdapterクラスがあります。

_private class PhotosPagerAdapter extends FragmentStatePagerAdapter{

    public PhotosPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return photos.size();   
    }

    @Override
    public Fragment getItem(int position) {
        ImageFragment f = new ImageFragment(position);
        return f;
    }

    @Override
    public int getItemPosition(Object object) {
        throw new RuntimeException();
        //return POSITION_NONE;
    }

}
_

おそらくお気づきのように、いつ呼び出されたかを確認したいので、getItemPositionにRuntimeExceptionをスローします。そして、自分の写真を含むリストに何かを追加するまで呼び出されません。次に、ImageFragmentクラス:

_public class ImageFragment extends Fragment{

    int position;
    Bitmap mBitmap;
    int width;
    int height;
    ImageView img;

    public ImageFragment(){
    }

    public ImageFragment(int position){
        this.position = position;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        img = new ImageView(container.getContext());
        img.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        width = container.getWidth();
        height = container.getHeight();

        loadBitmap();

        return img;
    }       

    public void loadBitmap(){
        if (img == null){
            return;
        }
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(photos.get(position), options);
        options.inSampleSize = calculateInSampleSize(options, width/2, height/2);
        options.inJustDecodeBounds = false;
        mBitmap = BitmapFactory
                .decodeFile(photos.get(position), options);         

        img.setImageBitmap(mBitmap);
    }


    @Override
    public void onDestroyView() {
        mBitmap.recycle();
        super.onDestroyView();
    }       
}
_

コードを修正しようとしたところ、コードがやや乱雑です...しかし、onDestroyView()を削除しても機能しません。 mPagerAdapter.notifyDataSetChanged()を(onResume()のように)呼び出さなければならないいくつかの場所に配置しましたが、結果はありません。私はそれでちょっと必死になっています。

18
wasyl

フラグメントページャーアダプターの処理は、PITAの場合があります。

役立つヒントをいくつか紹介します。

ViewPager PagerAdapterがビューを更新しない

ViewPagerを動的に更新しますか?

一般的に言えば、これは99%の時間で動作します...

次のように、PagerAdapterのgetItemPositionをオーバーライドします。

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

それらが機能しない場合もありますが、「ブルートフォース」メソッドを使用して、ビュー全体をもう一度(onCreate以降)再作成する必要があります...

37
logray

私はあなたのような同様の問題を抱えていました、いくつかの調査の後に、すでに存在するフラグメントの再作成を回避しながら、すべての可視/開始されたフラグメントを更新できる素敵なスクリプトを作成しました。

import Android.support.v4.app.Fragment;
import Android.support.v4.app.FragmentManager;
import Android.support.v4.app.FragmentStatePagerAdapter;
import Android.view.ViewGroup;

import Java.util.WeakHashMap;

/**
 * Created by TheCobra on 9/17/15.
 */
public abstract class FragmentAdvanceStatePagerAdapter extends FragmentStatePagerAdapter
{
    private WeakHashMap<Integer, Fragment> mFragments;

    public FragmentAdvanceStatePagerAdapter(FragmentManager fm)
    {
        super(fm);
        mFragments = new WeakHashMap<Integer, Fragment>();
    }

    @Override
    public Fragment getItem(int position)
    {
        Fragment item = getFragmentItem(position);
        mFragments.put(Integer.valueOf(position), item);
        return item;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object)
    {
        super.destroyItem(container, position, object);
        Integer key = Integer.valueOf(position);
        if (mFragments.containsKey(key))
        {
            mFragments.remove(key);
        }
    }

    @Override
    public void notifyDataSetChanged()
    {
        super.notifyDataSetChanged();
        for (Integer position : mFragments.keySet())
        {
            //Make sure we only update fragments that should be seen
            if (position != null && mFragments.get(position) != null && position.intValue() < getCount())
            {
                updateFragmentItem(position, mFragments.get(position));
            }
        }
    }

    @Override
    public int getItemPosition(Object object)
    {
        //If the object is a fragment, check to see if we have it in the hashmap
        if (object instanceof Fragment)
        {
            int position = findFragmentPositionHashMap((Fragment) object);
            //If fragment found in the hashmap check if it should be shown
            if (position >= 0)
            {
                //Return POSITION_NONE if it shouldn't be display
                return (position >= getCount()? POSITION_NONE : position);
            }
        }

        return super.getItemPosition(object);
    }

    /**
     * Find the location of a fragment in the hashmap if it being view
     * @param object the Fragment we want to check for
     * @return the position if found else -1
     */
    protected int findFragmentPositionHashMap(Fragment object)
    {
        for (Integer position : mFragments.keySet())
        {
            if (position != null &&
                mFragments.get(position) != null &&
                mFragments.get(position) == object)
            {
                return position;
            }
        }

        return -1;
    }

    public abstract Fragment getFragmentItem(int position);
    public abstract void updateFragmentItem(int position, Fragment fragment);
}

そのコードをファイル名「FragmentAdvanceStatePagerAdapter.Java」にコピーします。アダプターで、このアダプターから拡張して、「getFragmentItem()」と「updateFragmentItem()」をオーバーライドします。 notifydatachange()を呼び出すたびに、作成済みのすべてのフラグメントを使用してupdateFragmentItem()が呼び出されます。アダプターが新しいフラグメントを作成する必要がある場合、getFragmentItem()が呼び出されます。

多くの人々を救い、助けてくれることを願っています:)

幸運と幸せなプログラミング!!!

追伸このクラスを使用する場合、アダプタ「getItem()」は「getFragmentItem()」である必要があります。

4
TheCobra

POSITION_NONEを返し、すべてのフラグメントを再度作成する代わりに、私がここで提案したように行うことができます: ViewPagerを動的に更新しますか?

1
M-WaJeEh

POSITION_NONEを使用しないでください

if(fragmentManager.getFragments().contains(object))
    return POSITION_NONE;
else
    return POSITION_UNCHANGED;

致命的な例外を回避するには:Java.lang.IllegalStateException Fragment {}は現在FragmentManagerにありません

1
Tyler Davis