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


316

ViewPagerでコンテンツを更新できません。

FragmentPagerAdapterクラスのメソッドinstantiateItem()およびgetItem()の正しい使用法は何ですか?

私はgetItem()だけを使用してフラグメントをインスタンス化して返していました:

@Override
public Fragment getItem(int position) {
    return new MyFragment(context, paramters);
}

これはうまくいきました。内容を変更できない以外は。

だから私はこれを見つけました:ViewPager PagerAdapterがビューを更新していません

「私のアプローチは、instantiateItem()メソッドでインスタンス化されたビューにsetTag()メソッドを使用することです」

これを行うために、instantiateItem()を実装したいと思います。しかし、私は何を返さなければならないのか(タイプはObjectです)、そしてgetItem(int position)との関係は何ですか?

リファレンスを読んだ

  • public abstract Fragment getItem(int position)

    指定された位置に関連付けられたフラグメントを返します。

  • public Object instantiateItem(ViewGroupコンテナー、int位置)

    指定された位置にページを作成します。アダプターは、ここで指定されたコンテナーにビューを追加する必要がありますが、finishUpdate(ViewGroup)から戻るまでにこれが確実に行われるようにする必要があります。パラメーター

    コンテナーページが表示されるコンテナーを含むビュー。positionインスタンス化されるページの位置。

    戻り値

    新しいページを表すオブジェクトを返します。これはビューである必要はありませんが、ページの他のコンテナにすることができます。

まだ分​​かりません。

これが私のコードです。サポートパッケージv4を使用しています。

ViewPagerTest

public class ViewPagerTest extends FragmentActivity {
    private ViewPager pager;
    private MyFragmentAdapter adapter; 

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.pager1);

        pager = (ViewPager)findViewById(R.id.slider);

        String[] data = {"page1", "page2", "page3", "page4", "page5", "page6"};

        adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
        pager.setAdapter(adapter);

        ((Button)findViewById(R.id.button)).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                reload();
            }
        });
    }

    private void reload() {
        String[] data = {"changed1", "changed2", "changed3", "changed4", "changed5", "changed6"};
        //adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
        adapter.setData(data);
        adapter.notifyDataSetChanged();
        pager.invalidate();

        //pager.setCurrentItem(0);
    }
}

MyFragmentAdapter

class MyFragmentAdapter extends FragmentPagerAdapter {
    private int slideCount;
    private Context context;
    private String[] data;

    public MyFragmentAdapter(FragmentManager fm, int slideCount, Context context, String[] data) {
        super(fm);
        this.slideCount = slideCount;
        this.context = context;
        this.data = data;
    }

    @Override
    public Fragment getItem(int position) {
        return new MyFragment(data[position], context);
    }

    @Override
    public int getCount() {
        return slideCount;
    }

    public void setData(String[] data) {
        this.data = data;
    }

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

MyFragment

public final class MyFragment extends Fragment {
    private String text;

    public MyFragment(String text, Context context) {
        this.text = text;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.slide, null);
        ((TextView)view.findViewById(R.id.text)).setText(text);

        return view;
    }
}

ここにも同様の問題を持つ誰かがいます、答えはありません http://www.mail-archive.com/android-developers@googlegroups.com/msg200477.html


関連するコンポーネントをよりよく理解するには、個別の戻るナビゲーション履歴を持つタブ付きのViewPagerに関するチュートリアルを読むと役立つ場合があります。GitHubの実用的なサンプルと追加のリソースが含まれています。medium.com
@ nilan


この例はGitHubで確認できます。この例がお役に立てば幸いです。
Cabezas 2017

優れたシンプルなソリューション:stackoverflow.com/a/35450575/2162226
Gene Bo

Googleは最近、動的なフラグメント/ビューの更新を簡素化するViewPager2を導入しました。github.com/googlesamples/android-viewpager2で例を見るか、stackoverflow.com
Yves Delerm

回答:


605

FragmentPagerAdapterまたはFragmentStatePagerAdapterを使用するときはgetItem()、まったく触れず、まったく触れないことが最善instantiateItem()です。instantiateItem()- destroyItem()- isViewFromObject()PagerAdapter上のインターフェイスはFragmentPagerAdapterがはるかに簡単実装するために使用する低レベルのインターフェースであるgetItem()インターフェースを。

これに入る前に、私はそれを明確にすべきです

表示されている実際のフラグメントを切り替えたい場合は、FragmentPagerAdapterを避け、FragmentStatePagerAdapterを使用する必要があります。

この回答の以前のバージョンでは、例としてFragmentPagerAdapterを使用するという誤りがありました。FragmentPagerAdapterは、最初に表示された後はフラグメントを破棄しないため、機能しません。

リンクした投稿で提供されているsetTag()findViewWithTag()回避策はお勧めしません。あなたが発見したように、フラグメントを使用setTag()してfindViewWithTag()動作しないので、それは良い一致ではありません。

正しい解決策は、オーバーライドすることgetItemPosition()です。ときnotifyDataSetChanged()に呼び出され、ViewPager呼び出しgetItemPosition()、彼らは別の位置に移動または削除する必要があるかどうかを確認するために、そのアダプターのすべての項目に。

デフォルトでgetItemPosition()POSITION_UNCHANGED、を返します。つまり、「このオブジェクトはどこにでも問題ありません。破棄したり削除したりしないでください。」戻るPOSITION_NONEと、代わりに「このオブジェクトは表示しているアイテムではありません。削除してください」と言って問題を修正します。そのため、アダプター内のすべてのアイテムを削除して再作成する効果があります。

これは完全に正当な修正です!この修正により、notifyDataSetChangedはビューのリサイクルなしで通常のアダプタのように動作します。この修正を実装し、パフォーマンスが満足のいくものであれば、競争に参加できます。仕事が終わりました。

より優れたパフォーマンスが必要な場合は、より洗練getItemPosition()された実装を使用できます。文字列のリストからフラグメントを作成するページャーの例を次に示します。

ViewPager pager = /* get my ViewPager */;
// assume this actually has stuff in it
final ArrayList<String> titles = new ArrayList<String>();

FragmentManager fm = getSupportFragmentManager();
pager.setAdapter(new FragmentStatePagerAdapter(fm) {
    public int getCount() {
        return titles.size();
    }

    public Fragment getItem(int position) {
        MyFragment fragment = new MyFragment();
        fragment.setTitle(titles.get(position));
        return fragment;
    }

    public int getItemPosition(Object item) {
        MyFragment fragment = (MyFragment)item;
        String title = fragment.getTitle();
        int position = titles.indexOf(title);

        if (position >= 0) {
            return position;
        } else {
            return POSITION_NONE;
        }
    }
});

この実装では、新しいタイトルを表示するフラグメントのみが表示されます。まだリストにあるタイトルを表示しているフラグメントは、代わりにリスト内の新しい位置に移動され、リストに存在しなくなったタイトルを持つフラグメントは破棄されます。

フラグメントが再作成されていないが、とにかく更新する必要がある場合はどうなりますか?生きているフラグメントへの更新は、フラグメント自体によって適切に処理されます。結局のところ、これにはフラグメントがあるという利点があります。これは独自のコントローラーです。フラグメントは、リスナーまたはオブザーバーをの別のオブジェクトに追加しonCreate()、それをで削除してonDestroy()、更新自体を管理できます。getItem()ListViewまたは他のAdapterViewタイプのアダプターの場合のように、すべての更新コードを内部に配置する必要はありません。

最後にもう1つ、FragmentPagerAdapterがフラグメントを破棄しないからといって、getItemPositionがFragmentPagerAdapterで完全に役に立たないというわけではありません。このコールバックを使用して、ViewPagerでフラグメントを並べ替えることができます。ただし、FragmentManagerから完全に削除されることはありません。


4
動作しません。まだ何も更新されていません...コードを投稿しました。
Ixx

64
さて、問題を解決しました-FragmentPagerAdapterではなくFragmentStatePagerAdapterを使用する必要があります。FragmentPagerAdapterはFragmentManagerからフラグメントを削除することはなく、デタッチとアタッチのみを行います。詳細については、ドキュメントを確認してください。通常、永続的なフラグメントに対してのみFragmentPagerAdapterを使用します。私の例を修正して編集しました。
Bill Phillips

1
これについては後で確認します...回答ありがとうございます。そして、それがうまくいけば、私はあなたの答えを受け入れます。最後のコメントの前に、毎回新しいViewPagerを削除および追加するように実装しましたが、それは機能します。あまり良い解決策ではありませんが、今はそれを変更する時間はありません。
Ixx

12
アダプターのクラスをFragmentStatePagerAdapterに変更すると、問題がすべて解決しました。ありがとう!
Ixx

2
POSITION_NONEを返しても、を使用しFragmentStatePagerAdapterていると、フラグメントが削除され、新しいインスタンスが作成されていることがわかります。ただし、新しいインスタンスは、古いフラグメントの状態を含むsavedInstanceStateバンドルを受け取ります。フラグメントを完全に破棄して、バンドルが再度作成されたときにnullになるようにするにはどうすればよいですか?
2016

142

POSITION_NONEから戻り、getItemPosition()フルビューのレクリエーションを引き起こす代わりに、これを行います:

//call this method to update fragments in ViewPager dynamically
public void update(UpdateData xyzData) {
    this.updateData = xyzData;
    notifyDataSetChanged();
}

@Override
public int getItemPosition(Object object) {
    if (object instanceof UpdateableFragment) {
        ((UpdateableFragment) object).update(updateData);
    }
    //don't return POSITION_NONE, avoid fragment recreation. 
    return super.getItemPosition(object);
}

フラグメントはUpdateableFragmentインターフェースを実装する必要があります:

public class SomeFragment extends Fragment implements
    UpdateableFragment{

    @Override
    public void update(UpdateData xyzData) {
         // this method will be called for every fragment in viewpager
         // so check if update is for this fragment
         if(forMe(xyzData)) {
           // do whatever you want to update your UI
         }
    }
}

そしてインターフェース:

public interface UpdateableFragment {
   public void update(UpdateData xyzData);
}

あなたのデータクラス:

public class UpdateData {
    //whatever you want here
}

1
これは、MainActivityもインターフェイスを実装する必要があることを意味しますか??? ここで私を助けてください。現在の実装では、フラグメント間のコミュニケーターとしてMainActivityクラスを使用しているため、このソリューションについて混乱していました。
Rakeeb Rajbhandari 2013年

1
[OK]を私は私が更新しています完全な実装で別の場所で答えてきたFragment顔をして、動的:stackoverflow.com/questions/19891828/...
M-WaJeEh

@ M-WaJeEh多分いくつかの例をお願いします!!! 都市のリストを含むリストビューがあり、都市を選択した後、この都市に関する情報を含むビューページャー(3ページ)を開きます。それは大丈夫です。しかし、別の都市のビューページャーを選択すると、3D d page on refreshes the 1-st page only after swiping pages? thw 2ページのみが常に空白であると表示されます。感謝
SERG 2014

4
私の仕事の過去2.5日間に見たすべてのものの中で..これは私のために働いた唯一のものです..あらゆる種類のありがとう、ありがとう、spaciba、sukran .. n。
Orkun Ozen

2
ドラゴンズの母!、これは魅力のように機能し、唯一の解決策が私のために機能しました... thxたくさん!!
セバスティアン・ゲレロ

24

私が以前に直面したのと同じ問題にまだ直面している人のために、私がViewPager7個のフラグメントを持っているとき。これらのフラグメントがAPIサービスから英語のコンテンツをロードするためのデフォルトですが、ここで問題を設定アクティビティから言語を変更し、設定アクティビティが完了した後ViewPager、メインアクティビティでフラグメントを更新して、ユーザーからの言語選択と一致させ、ロードしますユーザーがここでアラビア語を選択した場合のアラビア語コンテンツ

1-上記のようにFragmentStatePagerAdapterを使用する必要があります。

2- mainActivityでonResumeをオーバーライドし、次のことを行いました

if (!(mPagerAdapter == null)) {
    mPagerAdapter.notifyDataSetChanged();
}

3-i getItemPosition()はmPagerAdapter のinをオーバーライドし、それを返すようにしましたPOSITION_NONE

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

魅力のように機能します


1
1つの状況以外で機能します。viewPagerで最後のアイテムを削除したとき。その後、リストから削除されません。
VladoPandžić16年

ビューページャーの現在のフラグメントの左側と右側の両方に動的にフラグメントを追加していました。これはうまくいきました!ありがとう。
h8pathak '19

15

私はこの問題に遭遇し、ようやく本日解決しました。そこで学んだことを書き留め、Androidを初めて使用する人ViewPagerや、私と同じように更新する人にとって役立つことを願っています。私はFragmentStatePagerAdapterAPIレベル17で使用しており、現在2つのフラグメントしかありません。正しくないことがあると思います。訂正してください。ありがとうございます。 ここに画像の説明を入力してください

  1. シリアル化されたデータをメモリにロードする必要があります。これは、使用して行うことができますCursorLoader/ AsyncTask/ Thread。自動的に読み込まれるかどうかは、コードによって異なります。を使用している場合CursorLoaderは、登録されたデータオブザーバーがあるため、自動ロードされます。

  2. を呼び出した後viewpager.setAdapter(pageradapter)getCount()フラグメントを構築するためにアダプターが常に呼び出されます。したがって、データがロードされている場合はgetCount()0を返すことができるため、データが表示されない場合にダミーフラグメントを作成する必要はありません。

  3. データが読み込まれた後、getCount()まだ0であるため、アダプターはフラグメントを自動的に作成しません。そのため、実際に読み込まれたデータ番号をから返すgetCount()ように設定し、アダプターのを呼び出すことができnotifyDataSetChanged()ます。ViewPagerメモリ内のデータによってフラグメント(最初の2つのフラグメントのみ)の作成を開始します。notifyDataSetChanged()返される前に行われます。次に、ViewPager必要な適切なフラグメントがあります。

  4. データベースとメモリの両方のデータが更新された場合(ライトスルー)、またはメモリ内のデータのみが更新された場合(ライトバック)、またはデータベース内のデータのみが更新された場合。最後の2つのケースで、データがデータベースからメモリに自動的にロードされない場合(上記のとおり)。ViewPagerページャアダプタは、単にメモリ内のデータを扱います。

  5. したがって、メモリ内のデータが更新されたら、アダプタのを呼び出すだけですnotifyDataSetChanged()。フラグメントはすでに作成されているので、戻るonItemPosition()前にアダプタが呼び出されnotifyDataSetChanged()ます。で何もする必要はありませんgetItemPosition()。その後、データが更新されます。


(memeoryで)データを更新した後、何もする必要がないことがわかりました。呼び出すnotifyDataSetChanged()だけで、自動的に更新されます。これは、使用するフラグメント(chartview付き)が自動的に更新されるためです。そうでない場合は、静的フラグメントのように、呼び出しonItemPositon()POSITION_NONE 申し訳ありませんが返されます
oscarthecat

その図を作成するためにどのツールが使用されたかについて誰かが知っていますか?
JuiCe

12

コードのdestroyDrawingCache()notifyDataSetChanged()でViewPagerを試してください。


3
こっちも一緒。素晴らしい作品をありがとうございます。私はFragments自分のビューページャーで使用していないため、特に苦労しました。ありがとうございます!
Seth

11

この問題を克服するために上記のすべてのソリューションをしようとし、また、のような他の同様の質問に多くのソリューションをしようとしているときにフラストレーションの時間後、このこのこのすべては、この問題を解決し、作るために私と一緒に失敗したViewPager古いものを破壊することFragmentと記入pagerして新しいFragments。私は次のように問題を解決しました:

1)次のようViewPagerに拡張するクラスを作成FragmentPagerAdapterします。

 public class myPagerAdapter extends FragmentPagerAdapter {

2)次のようにとのViewPagerストアのアイテムを作成します。titlefragment

public class PagerItem {
private String mTitle;
private Fragment mFragment;


public PagerItem(String mTitle, Fragment mFragment) {
    this.mTitle = mTitle;
    this.mFragment = mFragment;
}
public String getTitle() {
    return mTitle;
}
public Fragment getFragment() {
    return mFragment;
}
public void setTitle(String mTitle) {
    this.mTitle = mTitle;
}

public void setFragment(Fragment mFragment) {
    this.mFragment = mFragment;
}

}

3)次ViewPagerように、FragmentManagerインスタンスのコンストラクタを作成して、インスタンスをmy に格納classします。

private FragmentManager mFragmentManager;
private ArrayList<PagerItem> mPagerItems;

public MyPagerAdapter(FragmentManager fragmentManager, ArrayList<PagerItem> pagerItems) {
    super(fragmentManager);
    mFragmentManager = fragmentManager;
    mPagerItems = pagerItems;
}

4)再設定する方法を作成しadapter、以前のすべて削除することによって、新たなデータを有するデータfragmentからfragmentManager直接作ること自体をadapter新たに設定しfragment、次のように再び新しいリストから。

public void setPagerItems(ArrayList<PagerItem> pagerItems) {
    if (mPagerItems != null)
        for (int i = 0; i < mPagerItems.size(); i++) {
            mFragmentManager.beginTransaction().remove(mPagerItems.get(i).getFragment()).commit();
        }
    mPagerItems = pagerItems;
}

5)コンテナーから、ActivityまたはFragment新しいデータでアダプターを再初期化しないでください。メソッドを使用setPagerItemsして、次のように新しいデータで新しいデータを設定します。

ArrayList<PagerItem> pagerItems = new ArrayList<PagerItem>();
    pagerItems.add(new PagerItem("Fragment1", new MyFragment1()));
    pagerItems.add(new PagerItem("Fragment2", new MyFragment2()));

    mPagerAdapter.setPagerItems(pagerItems);
    mPagerAdapter.notifyDataSetChanged();

お役に立てば幸いです。


あなたは私の問題で私を助けることができるstackoverflow.com/questions/40149039/...
アルバート・

あなたはこの問題についてのヘルプ、私を喜ばせることができstackoverflow.com/questions/41547995/...
マムシ

10

何らかの理由で回答がまったく機能しなかったため、fragmentStatePagerAdapterでsuperを呼び出さずにrestoreStateメソッドをオーバーライドする必要がありました。コード:

private class MyAdapter extends FragmentStatePagerAdapter {

    // [Rest of implementation]

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {}

}

1
このSOの答えで他のすべてを試した後、これは私のために働いたものです。問題のPagerAdapterをホストするアクティビティに戻るアクティビティを終了()しています。この場合、すべてのフラグメントを再作成したいのですが、先ほど完了したアクティビティがフラグメントの描画に使用される状態を変更した可能性があるためです。
JohnnyLambada 2016年

OMG ..動作します..動作します..称賛:D私の場合、viewpagerの現在のアイテムオブジェクトを削除する必要があります。しかし、現在のフラグメントは、上記のメソッド/ステップをすべて試しても更新されません。
Rahul Khurana

3

Bill Phillipsが提供するソリューションを自分のニーズに合わせて少し修正しました

private class PagerAdapter extends FragmentStatePagerAdapter{
    Bundle oBundle;
    FragmentManager oFragmentManager;
    ArrayList<Fragment> oPooledFragments;

public PagerAdapter(FragmentManager fm) {
    super(fm);
    oFragmentManager=fm;

    }
@Override
public int getItemPosition(Object object) {

    Fragment oFragment=(Fragment)object;
    oPooledFragments=new ArrayList<>(oFragmentManager.getFragments());
    if(oPooledFragments.contains(oFragment))
        return POSITION_NONE;
    else
        return POSITION_UNCHANGED;
    } 
}

そのため、when が現在呼び出されているフラグメントのみがgetItemPosition()返されます。(これとそれに関連付けられているのはアクティビティではなくフラグメントに含まれていることに注意してください)POSITION_NONEFragmentManagergetItemPositionFragmentStatePagerViewPager


2

同様の問題がありましたが、既存のソリューション(ハードコードされたタグ名など)を信頼したくないので、M-WaJeEhのソリューションをうまく機能させることができませんでした。これが私の解決策です:

getItemで作成されたフラグメントへの参照を配列に保持しています。これは、configurationChangeやメモリ不足などが原因でアクティビティが破棄されない限り、正常に機能します(->アクティビティに戻ったときに、フラグメントが「getItem」が再度呼び出されることなく、したがって配列を更新せずに最後の状態に戻ります。 )。

この問題を回避するには、次のように、instantiateItem(ViewGroup、int)を実装し、そこで配列を更新します。

        @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Object o = super.instantiateItem(container, position);
        if(o instanceof FragmentX){
            myFragments[0] = (FragmentX)o;
        }else if(o instanceof FragmentY){
            myFragments[1] = (FragmentY)o;
        }else if(o instanceof FragmentZ){
            myFragments[2] = (FragmentZ)o;
        }
        return o;
    }

ですから、一方では自分に役立つ解決策を見つけて共有したかったのは嬉しいですが、他の誰かが同様のことを試みたかどうか、私がすべきでない理由があるかどうかも尋ねたかったのです。それはそのようですか?これまでのところ、それは私にとって非常にうまくいきます...


私はに関連する何かやったstackoverflow.com/a/23427215/954643をあなたはおそらくから項目を削除する必要がありますが、myFragments中にpublic void destroyItem(ViewGroup container, int position, Object object)あなたが古いfragement参照をつかむしないようにも。
qix 2014年

1

EventBusライブラリを使用してのFragmentコンテンツを更新していViewPagerます。ロジックはシンプルで、EventBusのドキュメントの方法と同じですFragmentPagerAdapterインスタンスを制御する必要はありません。コードはここにあります:

1:イベントを定義する

更新する必要があるメッセージを定義します。

public class UpdateCountEvent {
    public final int count;

    public UpdateCountEvent(int count) {
        this.count = count;
    }
}

2.加入者を準備する

更新が必要なフラグメントに以下のコードを記述します。

@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}

@Override
public void onStop() {
    EventBus.getDefault().unregister(this);  
    super.onStop();
}

public void onEvent(UpdateCountEvent event) {//get update message
    Toast.makeText(getActivity(), event.count, Toast.LENGTH_SHORT).show();
}

3.投稿イベント

その他のコード下記の書き込みActivityや他のFragment更新パラメータに必要

//input update message
EventBus.getDefault().post(new UpdateCountEvent(count));

1

FragmentStatePagerAdapterを使用する場合は、https://code.google.com/p/android/issues/detail?can = 2&start = 0&num = 100&q =&colspec = ID%20Type%20Status%20Owner%20Summary%をご覧ください。 20Stars&groupby =&sort =&id = 37990。FragmentStatePagerAdapterに問題があり、ユースケースに問題がある場合とそうでない場合があります。

また、リンクにも解決策はほとんどありません。要件に適したものはほとんどありません。


そのURLから解決策を見つけました。私のコードでは、この要点gist.github.com/ypresto/8c13cb88a0973d071a64から変更されたFragmentStatePagerAdapterを使用しましたが、想定どおりに機能し始めました。
ラファエル

涼しい。はい。リンクにもいくつかの解決策があります。
2016

1

私は同じ問題を抱えており、何度も検索してきました。stackoverflowまたはgoogleを介して与えられた答えは、私の問題の解決策ではありませんでした。私の問題は簡単でした。リストがあります。viewpagerでこのリストを表示します。リストの先頭に新しい要素を追加して、ビューページャーを更新すると、何も変更されません。私の最終的な解決策は、誰でも使用できる非常に簡単なものでした。新しい要素がリストに追加され、リストを更新したい場合。まず、viewpagerアダプターをnullに設定してから、アダプターを再作成し、iをviewpagerに設定します。

myVPager.setAdapter(null);
myFragmentAdapter = new MyFragmentAdapter(getSupportFragmentManager(),newList);
myVPager.setAdapter(myFragmentAdapter);

アダプターがFragmentStatePagerAdapterを拡張する必要があることを確認してください


1

@Bill Phillips Oneからの情報を組み込んだ私の実装は、データが変更された場合を除いて、ほとんどの場合フラグメントキャッシュを取得します。シンプルで、問題なく動作するようです。

MyFragmentStatePagerAdapter.java

private boolean mIsUpdating = false;
public void setIsUpdating(boolean mIsUpdating) {
        this.mIsUpdating = mIsUpdating;
    }


@Override
public int getItemPosition(@NonNull Object object) {

    if (mIsUpdating) {
        return POSITION_NONE;
    }
    else {
        return super.getItemPosition(object);
    }
}

MyActivity.java

mAdapter.setIsUpdating(true);
mAdapter.notifyDataSetChanged();
mAdapter.setIsUpdating(false);

0

私は非常に多くの異なるアプローチを試みてきましたが、実際に私の問題を解決するものはありません。以下は、皆さんが提供するソリューションを組み合わせて解決する方法です。みんな、ありがとう。

class PagerAdapter extends FragmentPagerAdapter {

    public boolean flag_refresh=false;

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

    @Override
    public Fragment getItem(int page) {
        FragmentsMain f;
        f=new FragmentsMain();
        f.page=page;
        return f;
    }

    @Override
    public int getCount() {
        return 4;
    }

    @Override
    public int getItemPosition(Object item) {
        int page= ((FragmentsMain)item).page;

        if (page == 0 && flag_refresh) {
            flag_refresh=false;
            return POSITION_NONE;
        } else {
            return super.getItemPosition(item);
        }
    }

    @Override
    public void destroyItem(View container, int position, Object object) {

        ((ViewPager) container).removeView((View) object);
    }
}

onResume()の後でページ0のみを更新したい。

 adapter=new PagerAdapter(getSupportFragmentManager());
 pager.setAdapter(adapter);

@Override
protected void onResume() {
    super.onResume();

    if (adapter!=null) {
        adapter.flag_refresh=true;
        adapter.notifyDataSetChanged();
    }
}

私のFragmentsMainには、更新したいページかどうかを教えてくれるパブリック整数の「ページ」があります。

public class FragmentsMain extends Fragment {

private Cursor cursor;
private static Context context;
public int page=-1;

0

私はパーティーに遅れていることを知っています。TabLayout#setupWithViewPager(myViewPager);直後に電話をかけて問題を解決しましたFragmentPagerAdapter#notifyDataSetChanged();


0

このソリューションは誰にとっても機能するわけではありませんが、私の場合、ViewPagerのすべてのFragmentは異なるクラスであり、一度に存在するのはそのうちの1つだけです。

この制約があれば、このソリューションは安全であり、本番環境で安全に使用できます。

private void updateFragment(Item item) {

    List<Fragment> fragments = getSupportFragmentManager().getFragments();
    for (Fragment fragment : fragments) {

        if (fragment instanceof MyItemFragment && fragment.isVisible()) {
            ((MyItemFragment) fragment).update(item);
        }

    }
}

同じフラグメントの複数のバージョンがある場合、この同じ戦略を使用して、それらのフラグメントのメソッドを呼び出し、更新するフラグメントであるかどうかを判断できます。


0

これは誰かに役立つかもしれません-私の場合、新しいページを挿入するとき、ビューページャーは既存のフラグメントの位置を2回要求していましたが、新しいアイテムの位置を要求していなかったため、誤った動作とデータが表示されませんでした。

  1. FragmentStatePagerAdapterのソースをコピーします(古くから更新されていないようです)。

  2. notifyDataSetChanged()をオーバーライドする

    @Override
    public void notifyDataSetChanged() {
        mFragments.clear();
        super.notifyDataSetChanged();
    }
  3. クラッシュを防ぐためにdestroyItem()に健全性チェックを追加します。

    if (position < mFragments.size()) {
        mFragments.set(position, null);
    }

0

上記のすべての回答と他のいくつかの投稿を調べましたが、まだ機能するものが見つかりませんでした(動的にタブを追加および削除するさまざまなフラグメントタイプを使用)。FWIWの次のアプローチが私にとってうまくいきました(他の誰かが同じ問題を抱えている場合に備えて)。

public class MyFragmentStatePageAdapter extends FragmentStatePagerAdapter {
    private static final String TAB1_TITLE = "Tab 1";
    private static final String TAB2_TITLE = "Tab 2";
    private static final String TAB3_TITLE = "Tab 3";

    private ArrayList<String> titles = new ArrayList<>();
    private Map<Fragment, Integer> fragmentPositions = new HashMap<>();


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


    public void update(boolean showTab1, boolean showTab2, boolean showTab3) {
        titles.clear();

        if (showTab1) {
            titles.add(TAB1_TITLE);
        }
        if (showTab2) {
            titles.add(TAB2_TITLE);
        }
        if (showTab3) {
            titles.add(TAB3_TITLE);
        }
        notifyDataSetChanged();
    }


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

    @Override
    public Fragment getItem(int position) {
        Fragment fragment = null;

        String tabName = titles.get(position);
        if (tabName.equals(TAB1_TITLE)) { 
            fragment =  Tab1Fragment.newInstance();
        } else if (tabName.equals(TAB2_TITLE)) {
            fragment =  Tab2Fragment.newInstance();
        } else if (tabName.equals(TAB3_TITLE)) {
            fragment =  Tab3Fragmen.newInstance();
        } 

        ((BaseFragment)fragment).setTitle(tabName);
        fragmentPositions.put(fragment, position);
        return fragment;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return titles.get(position);
    }

    @Override
    public int getItemPosition(Object item) {
        BaseFragment fragment = (BaseFragment)item;
        String title = fragment.getTitle();
        int position = titles.indexOf(title);

        Integer fragmentPosition = fragmentPositions.get(item);
        if (fragmentPosition != null && position == fragmentPosition) {
            return POSITION_UNCHANGED;
        } else {
            return POSITION_NONE;
        }
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        super.destroyItem(container, position, object);
        fragmentPositions.remove(object);
    }
}

0

フラグメントに基づいてフラグメントを再作成または再ロードする場合は、FragmentPagerAdapterの代わりにFragmentStatePagerAdapterを使用します。たとえば、FirstFragment以外のフラグメントを再ロードする場合は、次のようにインスタンスをチェックして位置を返すことができます。

 public int getItemPosition(Object item) {
    if(item instanceof FirstFragment){
       return 0;
    }
    return POSITION_NONE;
 }

0

instantiateItemのmFragments要素getItemPositionを変更する必要があります。

    if (mFragments.size() > position) {
        Fragment f = mFragments.get(position);

        if (f != null) {
            int newPosition = getItemPosition(f);
            if (newPosition == POSITION_UNCHANGED) {
                return f;
            } else if (newPosition == POSITION_NONE) {
                mFragments.set(position, null);
            } else {
                mFragments.set(newPosition, f);
            }
        }
    }

mFragmentsnotifyDataSetChanged()を呼び出しても、要素の位置は変更されないため、AndroidX FragmentStatePagerAdapter.javaベース。

ソース:https : //github.com/cuichanghao/infivt/blob/master/library/src/main/java/cc/cuichanghao/library/FragmentStatePagerChangeableAdapter.java

例:https : //github.com/cuichanghao/infivt/blob/master/app/src/main/java/cc/cuichanghao/infivt/MainActivityChangeablePager.kt

このプロジェクトを実行して、作業方法を確認できます。 https://github.com/cuichanghao/infivt

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.