Pertanyaan Cara menghancurkan fragmen lama di FragmentStatePagerAdapter


Saya ingin menerapkan ini: enter image description here
Saya menggunakan ViewPager dengan FragmentStatePagerAdapter.
Saya mulai dengan contoh dari halaman ini:
http://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.html

Ini adalah adaptor ViewPager saya:

    public static class MyAdapter extends FragmentStatePagerAdapter {
        public MyAdapter(FragmentManager fm) {
            super(fm);
        }

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

        @Override
        public Fragment getItem(int position) {
            return ArrayListFragment.newInstance(position);
        }

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

Setiap halaman dari ViewPager saya berisi ListView dengan beberapa data. Saat saya beralih ke halaman baru di ViewPager, memori RAM akan meningkat dengan sangat cepat.
Bagaimana cara menghapus fragmen lama?
Saya juga menggunakan ini tetapi tidak melakukan apa-apa:

public void destroyItem(ViewGroup container, int position, Object object) {

    FragmentManager manager = ((Fragment) object).getFragmentManager();
    FragmentTransaction trans = manager.beginTransaction();
    trans.remove((Fragment) object);
    trans.commit();

    super.destroyItem(container, position, object);
}

Ada juga penundaan 1-2 detik setelah saya beralih dengan cepat ke halaman baru atau halaman lama. Adakah teknik untuk menghilangkan penundaan itu. Jika saya beralih ke halaman baru dan menunggu selama 2 detik, maka pada tombol berikutnya tidak ada lagi penundaan.

Diuji pada Nexus 7.


32
2018-06-06 23:43


asal


Jawaban:


Anda tidak harus mencoba untuk mengganggu cara Android mengelola Anda Fragment implementasi. Default untuk setOffScreenPageLimit seharusnya sudah menjadi satu. Ini berarti Android akan menghancurkan fragmen lama saat memori hampir habis. Selama Anda tidak memiliki masalah memori, biarkan saja.

Alasan mengapa memori Anda meningkat adalah karena Android terus Fragment contoh di memori untuk dapat menghubungkan kembali ke mereka daripada harus memberi mereka instantiate. Saya sarankan akun Anda untuk kontingensi Anda Fragment contoh dihancurkan oleh OS, menyimpan keadaan mereka jika itu terjadi, dan biarkan OS melakukan tugasnya.

Penundaan yang Anda alami bisa disebabkan oleh beberapa komputasi intensif pada utas UI. Jika ya, saya sarankan untuk memindahkannya ke, misalnya, sebuah AsyncTask. Tanpa kode itu, bagaimanapun, hanya menebak apa yang mungkin menyebabkan masalah. Tetapi hanya ada penundaan awal menunjukkan bahwa Anda memuat sesuatu yang mungkin memblokir utas UI.

Memperbarui: Silahkan lihat https://stackoverflow.com/a/9646622/170781 yang menguraikan dengan sangat rapi bagaimana ViewPager pegangan Fragment contoh.


14
2017-08-21 08:59



Saya memiliki masalah yang sama. Tetapi dalam kasus saya, ViewPager ada di dalam bagian lain. dan setelah menghapus ViewPagerFragment dari FragmentManager, semua fragmen dari FragmentStatePagerAdapter tetap berada di pengelola fragmen. jadi setelah beberapa perubahan seperti itu OutOfMemoryError. Lalu saya mengaktifkan log FragmentManager dengan:

FragmentManager.enableDebugLogging(true);

Dan menemukan bahwa id dari setiap fragmen baru meningkat setiap waktu. Itu hanya terjadi dengan StatePagerAdapter. Untuk mengatasi masalah ini saya sebut hapus untuk setiap fragmen yang telah di-instantinasikan.

protected void dispatchOnDetach(Iterable<Fragment> fragments) {
    if (fragments == null)
        return;

    Activity aa = getActivity();
    if (aa == null)
        return;

    IBaseActivity ba = (IBaseActivity) aa;
    if (ba.isActivityStopped())
        return;

    FragmentManager frMan = ba.getSupportFragmentManager();
    FragmentTransaction frTr = frMan.beginTransaction();

    for (Fragment fr : fragments) {
        if (fr != null) {
            frTr.remove(fr);
        }
    }

    frTr.remove(this);
    frTr.commit();

}

Dalam kasusmu. jika Anda tidak mengubah ViewPager selama waktu proses adalah mungkin, bahwa pengumpul sampah tidak dapat menghancurkan fragmen Anda bahkan setelah menghapus dari manajer fragmen karena beberapa referensi kepada mereka. Anda harus memeriksa apakah beberapa kelas global menggunakannya.

Dan untuk tujuan optimasi, Anda dapat men-cache setiap fragmen yang di-instantinasi menggunakan SoftReference atau LruCache. Contoh:

public class MyAdapter extends FragmentStatePagerAdapter {

private final LruCache<Integer, Fragment> mCache;

public MyAdapter(FragmentManager fm) {
    super(fm);
    mCache = new LruCache<Integer, Fragment>(10);
}

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

@Override
public Fragment getItem(int position) {
    return mCache.get(position);
}

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

private class MyCache extends LruCache<Integer, Fragment> {

    public MyCache(int maxSize) {
        super(maxSize);
    }

    @Override
    protected Fragment create(Integer key) {
        return ArrayListFragment.newInstance(key);
    }
}
}

14
2017-08-21 14:55



Itu FragmentStatePagerAdapter sudah sangat hemat dengan memori karena menghancurkan yang tidak diperlukan fragmentssecara otomatis. Itu hanya membuat pandangan fragmen secara langsung kiri dan kanan dari item yang ditampilkan saat ini dan menghancurkan yang lain.

Contoh: Jadi setelah Anda menggesek ke arah yang benar, itu akan melakukan pra-pemuatan segera untuk menjadi tetangga kanan-fragmen dan menghancurkan fragmen yang sekarang menjadi dua slot di sebelah kiri fragmen yang ditampilkan saat ini.


3
2017-08-15 11:50



Saya pikir masalahnya bukan dengan ViewPager ada pada ListFragments. Jenis konten apa yang Anda tunjukkan pada mereka? Apakah Anda mengalokasikan banyak gambar? Dapatkah Anda memposting kode ListFragment Anda?

Saya lebih suka berkomentar, tetapi karena saya tidak punya cukup poin, saya berharap dapat membantu dengan mengedit tanggapan ini.


1
2017-08-20 13:19



ViewPager sendiri memiliki metode setOffscreenPageLimit yang memungkinkan Anda menentukan jumlah halaman yang disimpan oleh adaptor. Jadi serpihan Anda yang jauh akan hancur.

Agak sulit untuk mengatakan apa yang mungkin menjadi masalah khusus Anda karena saya tidak tahu apa yang dilakukan fragmen Anda. Dengan suara penundaan 1-2 detik tampaknya Anda mungkin melakukan beberapa pekerjaan pada utas UI. Juga apa lagi yang Anda lakukan dalam fragmen Anda yang memakan memori? Mungkin Anda memuat gambar ke beberapa cache memori statis dan tidak membebaskannya setelah penghapusan fragmen? Bisakah Anda memberikan kode fragmen Anda, sehingga saya bisa melihat apa yang dilakukannya?

Secara umum saya akan merekomendasikan akan membuang file HPROF dari aplikasi Anda saat itu membutuhkan memori tambahan dan menganalisis referensi melalui MAT (alat analisa memori). Anda jelas memiliki masalah kebocoran memori dan saya sangat meragukan masalahnya ada pada Fragmen yang tidak dihancurkan.

Jika Anda tidak tahu cara menganalisis tumpukan memori, ini bagus video. Saya tidak dapat menghitung berapa kali itu membantu saya mengidentifikasi dan menyingkirkan kebocoran memori di aplikasi saya.


1
2017-08-21 08:42



Timpa ini di FragmentStatePagerAdapter, perhatikan sedikit perubahan.

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    if (position >= getCount()) {
    FragmentManager manager = ((Fragment) object).getFragmentManager();
    FragmentTransaction trans = manager.beginTransaction();
    trans.remove((Fragment) object);
    trans.commit();
}

1
2018-02-02 09:16