Perbarui ViewPager secara dinamis?

316

Saya tidak dapat memperbarui konten di ViewPager.

Apakah penggunaan metode yang benar instantiateItem () dan getItem () di kelas FragmentPagerAdapter?

Saya hanya menggunakan getItem () untuk membuat instance dan mengembalikan fragmen saya:

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

Ini bekerja dengan baik. Kecuali saya tidak bisa mengubah konten.

Jadi saya menemukan ini: ViewPager PagerAdapter tidak memperbarui View

"Pendekatan saya adalah menggunakan metode setTag () untuk tampilan instantiated apa pun dalam metode instantiateItem ()"

Sekarang saya ingin mengimplementasikan instantiateItem () untuk melakukan itu. Tetapi saya tidak tahu apa yang harus saya kembalikan (tipenya adalah Object) dan apa hubungannya dengan getItem (posisi int)?

Saya membaca referensi :

  • public abstrak Fragmen getItem (posisi int)

    Kembalikan Fragmen yang terkait dengan posisi yang ditentukan.

  • InstantiateItem objek publik (wadah ViewGroup, posisi int)

    Buat halaman untuk posisi yang diberikan. Adaptor bertanggung jawab untuk menambahkan tampilan ke wadah yang diberikan di sini, meskipun itu hanya harus memastikan ini dilakukan pada saat ia kembali dari finishUpdate (ViewGroup). Parameter

    container Tampilan yang berisi halaman yang akan ditampilkan. posisi Posisi halaman yang akan dipakai.

    Kembali

    Mengembalikan Objek yang mewakili halaman baru. Ini tidak perlu menjadi Tampilan, tetapi bisa berupa wadah halaman lainnya.

tapi saya masih belum mengerti.

Ini kode saya. Saya menggunakan paket dukungan 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;
    }
}

Di sini ada juga seseorang dengan masalah yang sama, tidak ada jawaban http://www.mail-archive.com/[email protected]/msg200477.html

Ixx
sumber
Untuk mendapatkan pemahaman yang lebih baik tentang komponen-komponen yang terlibat, mungkin membantu untuk membaca tutorial saya tentang ViewPager dengan tab dengan riwayat navigasi belakang yang terpisah. Muncul dengan contoh kerja pada GitHub dan sumber daya tambahan: medium.com/@nilan/…
marktani
mendapat beberapa masalah stackoverflow.com/questions/40149039/...
albert
Anda dapat memeriksa contoh ini di GitHub . Saya harap contoh ini membantu Anda.
Cabezas
Solusi sederhana yang bagus: stackoverflow.com/a/35450575/2162226
Gene Bo
Google baru-baru ini memperkenalkan ViewPager2 yang menyederhanakan pembaruan Fragmen / Tampilan dinamis. Anda dapat melihat contoh di github.com/googlesamples/android-viewpager2 atau jawaban ini di stackoverflow.com/a/57393414/1333448
Yves Delerm

Jawaban:

605

Saat menggunakan FragmentPagerAdapter atau FragmentStatePagerAdapter, yang terbaik adalah berurusan dengan getItem()dan tidak menyentuh instantiateItem()sama sekali. The instantiateItem()- destroyItem()- isViewFromObject()antarmuka pada PagerAdapter adalah antarmuka tingkat rendah yang FragmentPagerAdapter penggunaan untuk melaksanakan lebih sederhanagetItem() antarmuka.

Sebelum membahas hal ini, saya harus mengklarifikasi hal itu

jika Anda ingin menonaktifkan fragmen aktual yang sedang ditampilkan, Anda perlu menghindari FragmentPagerAdapter dan menggunakan FragmentStatePagerAdapter.

Versi sebelumnya dari jawaban ini membuat kesalahan dengan menggunakan FragmentPagerAdapter sebagai contohnya - itu tidak akan berfungsi karena FragmentPagerAdapter tidak pernah menghancurkan sebuah fragmen setelah itu ditampilkan pertama kali.

Saya tidak merekomendasikan setTag()dan findViewWithTag()solusi yang disediakan di pos yang Anda tautkan. Seperti yang telah Anda temukan, gunakan setTag()danfindViewWithTag() tidak bekerja dengan fragmen, jadi itu bukan pasangan yang baik.

Solusi yang tepat adalah menimpanya getItemPosition(). Saat notifyDataSetChanged()dipanggil, ViewPager memanggilgetItemPosition() semua item dalam adaptornya untuk melihat apakah item tersebut perlu dipindahkan ke posisi yang berbeda atau dihapus.

Secara default, getItemPosition()mengembalikan POSITION_UNCHANGED, yang berarti, "Objek ini baik-baik saja, jangan dihancurkan atau dihapus." KembaliPOSITION_NONE memperbaiki masalah dengan mengatakan, "Objek ini bukan lagi item yang saya tampilkan, hapus saja." Jadi itu memiliki efek menghapus dan menciptakan kembali setiap item dalam adaptor Anda.

Ini adalah perbaikan yang sepenuhnya sah! Perbaikan ini membuat notifyDataSetChanged berperilaku seperti Adaptor biasa tanpa melihat daur ulang. Jika Anda menerapkan perbaikan ini dan kinerjanya memuaskan, Anda siap. Pekerjaan selesai.

Jika Anda membutuhkan kinerja yang lebih baik, Anda dapat menggunakan getItemPosition()implementasi yang lebih menarik . Berikut ini contoh pager yang membuat fragmen dari daftar string:

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;
        }
    }
});

Dengan implementasi ini, hanya fragmen yang menampilkan judul baru yang akan ditampilkan. Setiap fragmen yang menampilkan judul yang masih ada dalam daftar akan dipindahkan ke posisi baru mereka dalam daftar, dan fragmen dengan judul yang tidak lagi ada dalam daftar sama sekali akan dihancurkan.

Bagaimana jika fragmen belum dibuat ulang, tetapi tetap perlu diperbarui? Pembaruan untuk fragmen hidup paling baik ditangani oleh fragmen itu sendiri. Bagaimanapun, itulah keuntungan memiliki sebuah fragmen - itu adalah pengontrolnya sendiri. Sebuah fragmen dapat menambahkan pendengar atau pengamat ke objek lain onCreate(), dan kemudian menghapusnya onDestroy(), sehingga mengelola pembaruan itu sendiri. Anda tidak harus memasukkan semua kode pembaruan ke dalamnyagetItem() seperti yang Anda lakukan pada adaptor untuk ListView atau tipe AdapterView lainnya.

Satu hal terakhir - hanya karena FragmentPagerAdapter tidak menghancurkan sebuah fragmen tidak berarti bahwa getItemPosition sama sekali tidak berguna dalam FragmentPagerAdapter. Anda masih dapat menggunakan panggilan balik ini untuk menyusun ulang fragmen Anda di ViewPager. Itu tidak akan pernah menghapus mereka sepenuhnya dari FragmentManager.

Bill Phillips
sumber
4
Tidak berfungsi, masih belum memperbarui apa pun ... memposting kode saya.
Ixx
64
Oke, cari tahu masalahnya - Anda perlu menggunakan FragmentStatePagerAdapter daripada FragmentPagerAdapter. FragmentPagerAdapter tidak pernah menghapus fragmen dari FragmentManager, itu hanya melepaskan dan menempelkannya. Periksa dokumen untuk info lebih lanjut - secara umum, Anda hanya ingin menggunakan FragmentPagerAdapter untuk fragmen yang permanen. Saya telah mengedit contoh saya dengan koreksi.
Bill Phillips
1
Saya akan mengulas hal ini nanti ... terima kasih atas jawaban Anda. Dan kemudian saya menerima jawaban Anda jika berhasil. Sebelum komentar terakhir Anda, saya menerapkan untuk menghapus dan menambahkan ViewPager baru setiap kali dan itu berfungsi. Bukan solusi yang sangat bagus, tapi saya tidak punya waktu sekarang untuk mengubahnya.
Ixx
12
Anda benar, mengubah kelas adaptor ke FragmentStatePagerAdapter memperbaiki semua masalah saya. Terima kasih!
Ixx
2
Bahkan ketika saya mengembalikan POSITION_NONE, saat menggunakan FragmentStatePagerAdapter, saya dapat melihatnya menghapus fragmen saya dan membuat instance baru. Tetapi instance baru menerima BundelInstanceState yang disimpan dengan keadaan fragmen lama. Bagaimana saya bisa sepenuhnya menghancurkan fragmen sehingga Bundle menjadi nol ketika dibuat lagi?
Singed
142

Alih-alih kembali POSITION_NONEdari getItemPosition()dan menyebabkan rekreasi tampilan penuh, lakukan ini:

//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);
}

Fragmen Anda harus mengimplementasikan UpdateableFragmentantarmuka:

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
         }
    }
}

dan antarmuka:

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

Kelas data Anda:

public class UpdateData {
    //whatever you want here
}
M-WaJeEh
sumber
1
Apakah ini berarti bahwa MainActivity Anda juga perlu mengimplementasikan antarmuka ??? Tolong bantu saya di sini. Dalam implementasi saya saat ini, saya menggunakan kelas MainActivity saya sebagai komunikator antara fragmen, jadi saya bingung tentang solusi ini.
Rakeeb Rajbhandari
1
Ok saya telah menjawab di tempat lain dengan implementasi penuh di mana saya memperbarui Fragmentsecara dinamis, lihat: stackoverflow.com/questions/19891828/…
M-WaJeEh
@ M-WaJeEh mungkin beberapa contoh tolong !!! Saya memiliki daftar tampilan dengan daftar kota dan setelah memilih kota membuka viewpager (3 halaman) dengan informasi tentang kota ini. itu bekerja ok. tetapi setelah memilih tampilan halaman kota lain hanya menunjukkan halaman 3 d page on refreshes the 1-st page only after swiping pages? thw 2selalu kosong. terima kasih
SERG
4
di antara semua hal yang telah saya lihat selama 2,5 hari terakhir dalam kehidupan kerja saya .. ini adalah satu-satunya yang bekerja untuk saya .. semua jenis arigato, terima kasih, spaciba, sukran .. n.
Orkun Ozen
2
Bunda Naga !, ini bekerja seperti mantra, satu-satunya solusi yang bekerja untuk saya ... terima kasih banyak !!
Sebastián Guerrero
24

bagi mereka yang masih menghadapi masalah yang sama yang saya hadapi sebelumnya ketika saya memiliki ViewPager7 fragmen. default untuk fragmen ini untuk memuat konten bahasa Inggris dari APIlayanan tetapi masalah di sini bahwa saya ingin mengubah bahasa dari aktivitas pengaturan dan setelah menyelesaikan kegiatan pengaturan saya ingin ViewPagerdalam kegiatan utama untuk menyegarkan fragmen agar sesuai dengan pilihan bahasa dari pengguna dan memuat konten Arab jika pengguna memilih bahasa Arab di sini apa yang saya lakukan untuk bekerja sejak pertama kali

1- Anda harus menggunakan FragmentStatePagerAdapter seperti yang disebutkan di atas.

2- pada mainActivity saya menimpa onResume dan melakukan hal berikut

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

3-i getItemPosition()meng -override di mPagerAdapter dan membuatnya kembali POSITION_NONE.

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

bekerja seperti pesona

Ziad Gholmish
sumber
1
Bekerja kecuali dalam satu situasi. Ketika Anda menghapus item terakhir di viewPager. Maka itu tidak menghapus dari daftar.
Vlado Pandžic
Saya menambahkan fragmen ke sisi kiri dan kanan dari fragmen saat ini di viewpager secara dinamis. Yang ini berhasil! Terima kasih.
h8pathak
15

Saya telah menemui masalah ini dan akhirnya menyelesaikannya hari ini, jadi saya menuliskan apa yang telah saya pelajari dan saya harap ini membantu bagi seseorang yang baru mengenal Android ViewPagerdan memperbarui seperti yang saya lakukan. Saya menggunakan FragmentStatePagerAdapterAPI level 17 dan saat ini hanya memiliki 2 fragmen. Saya pikir pasti ada sesuatu yang tidak benar, tolong perbaiki saya, terima kasih. masukkan deskripsi gambar di sini

  1. Data berseri harus dimuat ke dalam memori. Ini bisa dilakukan menggunakan CursorLoader/ AsyncTask/ Thread. Apakah itu dimuat secara otomatis tergantung pada kode Anda. Jika Anda menggunakan CursorLoader, ini dimuat secara otomatis karena ada pengamat data terdaftar.

  2. Setelah Anda menelepon viewpager.setAdapter(pageradapter), adaptor getCount()terus dipanggil untuk membuat fragmen. Jadi jika data sedang dimuat, getCount()dapat mengembalikan 0, sehingga Anda tidak perlu membuat fragmen dummy karena tidak ada data yang ditampilkan.

  3. Setelah data dimuat, adaptor tidak akan membuat fragmen secara otomatis karena getCount()masih 0, sehingga kita dapat mengatur nomor data yang sebenarnya dimuat untuk dikembalikan oleh getCount(), lalu memanggil adaptor notifyDataSetChanged(). ViewPagermulai membuat fragmen (hanya 2 fragmen pertama) dengan data dalam memori. Itu dilakukan sebelum notifyDataSetChanged()dikembalikan. Maka ViewPagermemiliki fragmen yang tepat yang Anda butuhkan.

  4. Jika data dalam database dan memori diperbarui (tulis melalui), atau hanya data dalam memori yang diperbarui (tulis kembali), atau hanya data dalam database yang diperbarui. Dalam dua kasus terakhir jika data tidak secara otomatis dimuat dari database ke memori (seperti yang disebutkan di atas). The ViewPagerdan adaptor pager hanya berurusan dengan data dalam memori.

  5. Jadi ketika data dalam memori diperbarui, kita hanya perlu memanggil adaptor notifyDataSetChanged(). Karena fragmen sudah dibuat, adaptor onItemPosition()akan dipanggil sebelum notifyDataSetChanged()kembali. Tidak ada yang perlu dilakukan di getItemPosition(). Kemudian data diperbarui.

oscarthecat
sumber
Saya telah menemukan apa-apa yang perlu dilakukan setelah Anda memperbarui data (dalam memeory), panggil notifyDataSetChanged()saja kemudian baru saja diperbarui secara otomatis, karena fragmen (dengan chartview) yang saya gunakan akan menyegarkan sendiri. jika tidak, seperti fragmen statis, saya harus menelepon onItemPositon()dan mengembalikan POSITION_NONE maaf tentang hal itu
oscarthecat
Adakah yang tahu alat apa yang digunakan untuk membuat diagram itu?
JuiCe
12

Coba destroyDrawingCache()di ViewPager setelah notifyDataSetChanged()di kode Anda.

czaku
sumber
3
Sama disini. Terima kasih banyak. Saya mengalami kesulitan terutama karena saya tidak menggunakan Fragmentspager tampilan saya. Jadi terima kasih
Seth
11

Setelah berjam-jam frustrasi ketika mencoba semua solusi di atas untuk mengatasi masalah ini dan juga mencoba banyak solusi pada pertanyaan serupa lainnya seperti ini , ini dan ini yang semuanya GAGAL dengan saya untuk menyelesaikan masalah ini dan membuat ViewPageruntuk menghancurkan yang lama Fragmentdan mengisi pagerdengan yang baru Fragment. Saya telah memecahkan masalah sebagai berikut:

1) Buat ViewPagerkelas untuk diperluas FragmentPagerAdaptersebagai berikut:

 public class myPagerAdapter extends FragmentPagerAdapter {

2) Buat Item untuk ViewPagertoko itu titledan fragmentsebagai berikut:

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) Buat konstruktor dari ViewPagertake my FragmentManagerinstance untuk menyimpannya di classsebagai berikut:

private FragmentManager mFragmentManager;
private ArrayList<PagerItem> mPagerItems;

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

4) Buat metode untuk mengatur ulang adapterdata dengan data baru dengan menghapus semua sebelumnya fragmentdari fragmentManageritu sendiri secara langsung untuk membuat adapteruntuk mengatur yang baru fragmentdari daftar baru lagi sebagai berikut:

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) Dari wadah Activityatau Fragmentjangan inisialisasi ulang adaptor dengan data baru. Atur data baru melalui metode setPagerItemsdengan data baru sebagai berikut:

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();

Saya harap ini membantu.

Sami Eltamawy
sumber
dapatkah Anda membantu saya dalam masalah saya stackoverflow.com/questions/40149039/…
albert
bisakah Anda membantu saya dengan masalah ini stackoverflow.com/questions/41547995/…
viper
10

Untuk beberapa alasan tidak ada jawaban yang bekerja untuk saya, jadi saya harus mengganti metode restoreState tanpa memanggil super di fragmentStatePagerAdapter. Kode:

private class MyAdapter extends FragmentStatePagerAdapter {

    // [Rest of implementation]

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

}
hordurh
sumber
1
Setelah mencoba semua yang lain dalam jawaban SO ini, ini adalah yang bekerja untuk saya. Saya selesai () melakukan aktivitas yang kembali ke Aktivitas yang menghosting PagerAdapter yang dimaksud. Saya ingin semua fragmen saya dibuat ulang dalam kasus ini karena Aktivitas yang baru saja saya selesaikan mungkin telah mengubah keadaan yang digunakan untuk menggambar fragmen.
JohnnyLambada
OMG .. berfungsi .. berfungsi .. pujian: D Dalam kasus saya, saya perlu menghapus objek item viewpager saat ini. tetapi fragmen saat ini tidak diperbarui setelah mencoba semua metode / langkah di atas.
Rahul Khurana
3

Saya sedikit memodifikasi solusi yang disediakan oleh Bill Phillips agar sesuai dengan kebutuhan saya

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;
    } 
}

sehingga getItemPosition()kembali POSITION_NONEhanya untuk orang-fragmen yang saat ini di FragmentManagersaat getItemPositiondisebut. (Perhatikan bahwa ini FragmentStatePagerdan yang ViewPagerterkait dengannya terkandung dalam Fragmen bukan dalam Aktivitas)

tunggu
sumber
2

Saya memiliki masalah yang sama tetapi tidak ingin mempercayai solusi yang ada (nama tag berkode keras dll.) Dan saya tidak bisa membuat solusi M-WaJeEh bekerja untuk saya. Ini solusinya:

Saya menyimpan referensi untuk fragmen yang dibuat di getItem dalam sebuah array. Ini berfungsi dengan baik selama aktivitas tidak dihancurkan karena perubahan konfigurasi atau kurangnya memori atau apa pun (-> ketika kembali ke aktivitas, fragmen kembali ke keadaan terakhir mereka tanpa 'getItem' dipanggil lagi dan dengan demikian tanpa memperbarui array ).

Untuk menghindari masalah ini, saya menerapkan instantiateItem (ViewGroup, int) dan memperbarui array saya di sana, seperti ini:

        @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;
    }

Jadi, di satu sisi saya senang bahwa saya menemukan solusi yang berfungsi untuk saya dan ingin membaginya dengan Anda, tetapi saya juga ingin bertanya apakah ada orang lain yang mencoba sesuatu yang serupa dan apakah ada alasan mengapa saya tidak boleh lakukan seperti itu Sejauh ini bekerja sangat baik untuk saya ...

jpm
sumber
Saya telah melakukan sesuatu yang terkait di stackoverflow.com/a/23427215/954643 , meskipun Anda mungkin harus menghapus item dari myFragmentsdalam public void destroyItem(ViewGroup container, int position, Object object)juga sehingga Anda tidak mengambil referensi frmentasi basi.
qix
1

Saya menggunakan perpustakaan EventBus untuk memperbarui Fragmentkonten di ViewPager. Logikanya sederhana, seperti halnya dokumen EventBus gimana caranya . Tidak perlu dikendalikanFragmentPagerAdapter instance. Kode di sini:

1: Tentukan acara

Tentukan pesan mana yang perlu diperbarui.

public class UpdateCountEvent {
    public final int count;

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

2. Persiapkan pelanggan

Tulis kode di bawah ini dalam Fragmen yang perlu diperbarui.

@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.Post acara

Tulis kode di bawah ini di lain Activityatau yang lain Fragmentyang perlu memperbarui parameter

//input update message
EventBus.getDefault().post(new UpdateCountEvent(count));
Fantasi Fang
sumber
1

Jika Anda ingin menggunakan FragmentStatePagerAdapter, silakan lihat di 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 . Ada masalah dengan FragmentStatePagerAdapter yang mungkin atau mungkin tidak mengganggu kasus penggunaan Anda.

Juga, tautan juga memiliki beberapa solusi. Beberapa mungkin sesuai dengan kebutuhan Anda.

cgr
sumber
Dari URL itu saya menemukan solusi. Saya menggunakan FragmentStatePagerAdapter yang dimodifikasi dari gist gist.github.com/ypresto/8c13cb88a0973d071a64 dalam kode saya dan mulai berfungsi sebagaimana mestinya.
Rafael
Keren. Iya. Tautan juga memiliki beberapa solusi.
cgr
1

Saya telah mengalami masalah yang sama dan saya telah mencari terlalu banyak. Setiap jawaban yang diberikan di stackoverflow atau melalui google bukanlah solusi untuk masalah saya. Masalah saya mudah. Saya punya daftar, saya tampilkan daftar ini dengan viewpager. Ketika saya menambahkan elemen baru ke kepala daftar dan saya menyegarkan tak berguna viewpager berubah. Solusi terakhir saya sangat mudah digunakan siapa saja. Ketika elemen baru ditambahkan ke daftar dan ingin menyegarkan daftar. Pertama-tama atur adaptor viewpager ke nol, kemudian buat kembali adaptor dan atur i untuk itu ke viewpager.

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

Pastikan adaptor Anda harus memperpanjang FragmentStatePagerAdapter

nebyan
sumber
1

Berikut ini adalah implementasi saya yang menggabungkan info dari @Bill Phillips One mendapat caching fragmen sebagian besar waktu, kecuali ketika data telah berubah. Sederhana, dan sepertinya berfungsi dengan baik.

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);
voam
sumber
0

Saya telah mencoba banyak pendekatan berbeda, tidak ada yang benar-benar menyelesaikan masalah saya. Di bawah ini adalah bagaimana saya menyelesaikannya dengan campuran solusi yang disediakan oleh Anda semua. Terimakasih semuanya.

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);
    }
}

Saya hanya ingin me-refresh halaman 0 setelah onResume ().

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

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

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

Di FragmentsMain saya, ada "halaman" bilangan bulat publik, yang dapat memberi tahu saya apakah itu halaman yang ingin saya segarkan.

public class FragmentsMain extends Fragment {

private Cursor cursor;
private static Context context;
public int page=-1;
Ted Hsieh
sumber
0

Saya tahu saya terlambat untuk pesta. Saya telah memperbaiki masalah dengan menelepon TabLayout#setupWithViewPager(myViewPager);setelahnyaFragmentPagerAdapter#notifyDataSetChanged();

theapache64
sumber
0

Solusi ini tidak akan bekerja untuk semua orang, tetapi dalam kasus saya, setiap Fragmen dalam ViewPager saya adalah kelas yang berbeda, dan hanya satu dari mereka yang pernah ada pada suatu waktu.

Dengan batasan ini, solusi ini aman dan harus aman digunakan dalam produksi.

private void updateFragment(Item item) {

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

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

    }
}

Jika Anda memiliki beberapa versi dari fragmen yang sama, Anda dapat menggunakan strategi yang sama ini untuk memanggil metode pada fragmen tersebut untuk menentukan apakah itu fragmen yang ingin Anda perbarui.

Kevin Grant
sumber
0

Ini mungkin bisa membantu seseorang - dalam kasus saya saat memasukkan halaman baru, pager tampilan meminta posisi fragmen yang ada dua kali, tetapi tidak menanyakan posisi item baru, menyebabkan perilaku yang salah dan data tidak ditampilkan.

  1. Salin sumber untuk untuk FragmentStatePagerAdapter (tampaknya belum diperbarui dalam usia).

  2. Ganti notifyDataSetChanged ()

    @Override
    public void notifyDataSetChanged() {
        mFragments.clear();
        super.notifyDataSetChanged();
    }
  3. Tambahkan cek kewarasan untuk destroyItem () untuk mencegah crash:

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

Saya telah memeriksa semua jawaban di atas dan sejumlah posting lainnya tetapi masih tidak dapat menemukan sesuatu yang bekerja untuk saya (dengan berbagai jenis fragmen bersamaan dengan menambahkan dan menghapus tab secara dinamis). FWIW mengikuti pendekatan adalah apa yang berhasil untuk saya (kalau-kalau ada orang lain yang memiliki masalah yang sama).

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);
    }
}
John O'Reilly
sumber
0

Gunakan FragmentStatePagerAdapter alih-alih FragmentPagerAdapter jika Anda ingin membuat ulang atau memuat ulang fragmen berdasarkan indeks Misalnya, jika Anda ingin memuat ulang fragmen selain FirstFragment, Anda dapat memeriksa instance dan mengembalikan posisi seperti ini

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

Anda perlu mengubah elemen mFragments instantiateItem 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);
            }
        }
    }

Berbasis AndroidX FragmentStatePagerAdapter.java, karena mFragments posisi elemen tidak berubah ketika memanggil notifyDataSetChanged ().

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

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

Anda dapat menjalankan proyek ini untuk mengonfirmasi cara kerjanya. https://github.com/cuichanghao/infivt

changhao cui
sumber