ViewPager.setOffscreenPageLimit (0) tidak berfungsi seperti yang diharapkan

100

Fragmen yang saya gunakan dalam ViewPagercontoh saya cukup intensif sumber daya, jadi saya hanya ingin memuat satu per satu. Ketika saya mencoba yang berikut ini:

mViewPager.setOffscreenPageLimit(0);
mViewPager.setAdapter(mPagerAdapter);

FragmentStatePagerAdapter.getItem(int position)Fungsi override saya dipanggil 3 kali, itulah yang terjadi saat saya memanggil mViewPager.setOffscreenPageLimit(1). Saya berharap itu hanya dipanggil sekali, karena saya menentukan 0 halaman di luar layar.

Saya yakin saya memanggil semuanya dengan benar, karena jika saya menelepon mViewPager.setOffscreenPageLimit(2), FragmentStatePagerAdapter.getItem(int position)akan dipanggil 5 kali seperti yang saya harapkan.

Apakah ViewPager memerlukan minimal 1 halaman di luar layar, atau apakah saya melakukan kesalahan di sini?

Chris Lacy
sumber
9
Saya telah menambahkan permintaan fitur: code.google.com/p/android/issues/detail?id=56667
Tandai
Saya hanya memiliki 3 tab dan pengaturan ViewPager.setOffscreenPageLimit(2)berfungsi untuk saya. CobaViewPager.setOffscreenPageLimit(totTabs - 1)
sibin

Jawaban:

112

Apakah ViewPager memerlukan minimal 1 halaman di luar layar

Iya. Jika saya membaca kode sumber dengan benar, Anda seharusnya mendapatkan peringatan tentang ini di LogCat, seperti:

Requested offscreen page limit 0 too small; defaulting to 1
CommonsWare
sumber
6
Ini bukan solusi! Saya ingin hanya memuat 1 fragmen bukan 2. Tentunya ini mungkin entah bagaimana?
HGPB
14
@Haraldo: "Tentunya ini mungkin entah bagaimana?" - tidak dengan ViewPager. ViewPagermembuat fragmen ini sehingga tampilan tersebut ada, sehingga pengguna dapat menggeser di antara tampilan, dengan efek animasi yang menunjukkan tampilan lama meluncur dari layar dan tampilan baru meluncur ke layar. Anda dipersilakan untuk mencoba menulis sendiri ViewPageryang bisa menggesek di antara hal-hal yang tidak ada. Anda dapat membaca lebih lanjut tentang ini di code.google.com/p/android/issues/detail?id=56667#c3
CommonsWare
2
Ya, saya telah membaca terbitan ini. Tidak logis. Saya berharap bisa setOffscreenPageLimit(0)0. Kemudian saya bisa menghadapi konsekuensinya sendiri. Fragmen kosong default bisa menjadi placeholder misalnya sampai fragmen tersebut dimuat. Semuanya bisa terjadi di luar thread UI. Pokoknya aku belum terlalu memikirkannya.
HGPB
5
@Haraldo: "Fragmen kosong default dapat menjadi placeholder misalnya sampai fragmen tersebut dimuat" - Anda dipersilakan untuk memiliki placeholder di fragmen Anda hari ini, dengan implementasi yang sudah ada ViewPager, yang Anda ganti dengan konten sebenarnya jika tersedia .
CommonsWare
2
onPageChangeListener sepertinya solusinya.
alicanbatur
123

Cara terbaik yang saya temukan adalah setUserVisibleHint
menambahkan ini ke fragmen Anda

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) {
        // load data here
    }else{
       // fragment is no longer visible
    }
}
Tyler Davis
sumber
1
+++++ untuk solusi ini !!! terima kasih, setelah menambahkan kode ini saya mendapat NPL untuk pertama kalinya, saya baru saja menambahkan blok coba tangkap dan itu berfungsi sempurna untuk saya !!!
Bhavin Chauhan
1
Saat menggunakannya, ia tidak memuat tanggal di secondViewPager Fragment, di fragmen kedua data pemuatannya dari fragmen ketiga. Bisakah seseorang membantu saya?
Arshad
Apakah saya melewatkan sesuatu, setUserVisibleHint dipanggil sebelum onCreateView
Anton Makov
Solusi terbaik sekarang tidak digunakan lagi
M.Sameer
@ M.Sameer ada alternatif lain untuk setUserVisibleHint telah merusak?
Yudi karma
8

Anda bisa mencoba seperti ini:

public abstract class LazyFragment extends Fragment {
    protected boolean isVisible;
    /**
     * 在这里实现Fragment数据的缓加载.
     * @param isVisibleToUser
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if(getUserVisibleHint()) {
            isVisible = true;
            onVisible();
        } else {
            isVisible = false;
            onInvisible();
        }
    }
    protected void onVisible(){
        lazyLoad();
    }
    protected abstract void lazyLoad();
    protected void onInvisible(){}

protected abstract void lazyLoad();
protected void onInvisible(){}
Terry
sumber
jawaban terbaik itu!
Radesh
7

Tambahkan Pertama

   boolean isFragmentLoaded = false;

dari

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser && !isFragmentLoaded) {
        //Load Your Data Here like.... new GetContacts().execute();

        isFragmentLoaded = true;
    }
else{
     }
}
Arpit J.
sumber
6
tetapi metode ini memanggil sebelum onCreateView
AndroidGeek
2

ViewPager default untuk memuat halaman berikutnya (Fragment) yang tidak dapat Anda ubah dengan setOffscreenPageLimit (0). Tapi Anda bisa melakukan sesuatu untuk diretas. Anda bisa mengimplementasikan fungsi onPageSelected dalam Aktivitas yang berisi ViewPager. Di Fragmen berikutnya (yang tidak ingin Anda muat), Anda menulis fungsi, katakanlah showViewContent () tempat Anda memasukkan semua kode init yang memakan sumber daya dan tidak melakukan apa pun sebelum metode onResume (). Kemudian panggil fungsi showViewContent () di dalam onPageSelected. Semoga ini bisa membantu.

Friends_little_black
sumber
1

ini mungkin utas lama tetapi tampaknya ini berhasil untuk saya. Ganti fungsi ini:

@Override
public void setMenuVisibility(boolean menuVisible) { 
    super.setMenuVisibility(menuVisible);

    if ( menuVisible ) {
        /**
         * Load your stuffs here.
         */
    } else  { 
        /**
         * Fragment not currently Visible.
         */
    } 
}

selamat coding ...

ralphgabb.dll
sumber
ada apa di webview? Saya sarankan Anda membuat utas baru untuk itu.
ralphgabb
1

dalam kasus saya, saya ingin memulai beberapa animasi dalam tampilan, tetapi dengan setUserVisibleHint mendapat beberapa masalah ...
solusi saya adalah:

1 / addOnPageChangeListener untuk adaptor Anda:

mViewPager.addOnPageChangeListener(this);

2 / implementasikan OnPageChangeListener:

public class PagesFragment extends Fragment implements ViewPager.OnPageChangeListener

3 / timpa 3 metode:

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{

}

@Override
public void onPageSelected(int position)
{ 
}

@Override
public void onPageScrollStateChanged(int state)
{
}

4 / deklarasikan dan lakukan inisialisasi variabel ini di kelas Anda

private static int mTabState = 1;

pemberitahuan : saya memiliki tiga fragmen di adaptor saya, dan menggunakan mTabState untuk setCurrentItem dan posisi adaptor saat ini yang mengenali fragmen mana yang ditampilkan kepada pengguna tepat waktu ... 5 / dalam metode onPageSelected tambahkan kode ini:

if (mTabState == 0 || position == 0)
    {
        Intent intent = new Intent("animation");
        intent.putExtra("current_position", position);
        LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
    }

jika halaman sebelumnya atau halaman saat ini adalah halaman 0 (fragmen di posisi 0) maka lakukan hal ini

6 / sekarang di kelas fragmen Anda (fragmen di posisi 0 adaptor), Anda harus membuat penerima siaran dan mendaftarkannya dalam metode onResume dan membatalkan pendaftarannya pada metode onPause:

BroadcastReceiver broadcastReceiver = new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        if (Objects.equals(intent.getAction(), "animation"))
        {
            int currentPosition = intent.getIntExtra("current_position", 0);
            if (currentPosition == 0)
            {
                startAnimation();
                setViewsVisible();
            } else
            {
                setViewsInvisible();
            }
        }
    }
};

@Override
public void onResume()
{
    super.onResume();
    LocalBroadcastManager.getInstance(mContext).registerReceiver(broadcastReceiver, new IntentFilter("animation"));
}

@Override
public void onPause()
{
    super.onPause();
    LocalBroadcastManager.getInstance(mContext).unregisterReceiver(broadcastReceiver);
}

ringkasan: Saya memiliki Penyihir Adaptor Pager Fragmen yang menunjukkan Tiga Fragmen di dalamnya, saya ingin menampilkan beberapa Animasi pada Tampilan dalam Fragmen di Posisi 0 Adaptor, Untuk ini saya menggunakan BroadcastReceiver. Ketika Fragmen Dipilih Saya memulai metode Animasi dan menunjukkan Tampilan kepada Pengguna, Ketika Fragmen tidak Ditampilkan kepada Pengguna, saya mencoba untuk Tampilan Tak Terlihat ...

AREF
sumber
1

Silakan Coba Kode Ini untuk mengatasi masalah menyegarkan tampilan di Viewpager ....

/* DO NOT FORGET! The ViewPager requires at least “1” minimum OffscreenPageLimit */
int limit = (mAdapter.getCount() > 1 ? mAdapter.getCount() - 1 : 1);
mViewPager.setOffscreenPageLimit(limit);
Abhijeet Sharma
sumber
0

untuk fungsi "instantiateItem", siapkan saja fragmennya, tetapi jangan memuat konten yang berat.

Gunakan "onPageChangeListener", sehingga setiap kali Anda membuka halaman tertentu, Anda memuat kontennya yang berat dan menampilkannya.

pengembang android
sumber
0

Saya memiliki masalah yang sama. Saya menemukan beberapa kode berguna di situs ini dan mengubahnya.

Min int untuk mViewPager.setOffscreenPageLimit (...); adalah 1, jadi meskipun Anda mengubahnya menjadi 0 Anda masih akan memiliki 2 halaman yang dimuat.

Hal pertama yang harus dilakukan adalah membuat sebuah int statis yang akan kita panggil maxPageCount dan mengganti metode FragmentStatePagerAdapter getCount () untuk mengembalikan maxPageCount:

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

Buat kemudian metode statis yang dapat diakses dari mana saja di program yang memungkinkan Anda untuk mengubah maxCount ini:

public static void addPage(){
    maxPageCount++; //or maxPageCount = fragmentPosition+2
    mFragmentStatePagerAdapter.notifyDataSetChanged(); //notifyDataSetChanged is important here.
}

Sekarang inisialisasi maxPageCount ke 1. Kapan pun Anda mau, Anda dapat menambahkan halaman lain. Dalam kasus saya ketika saya membutuhkan pengguna untuk memperlakukan halaman saat ini terlebih dahulu sebelum menghasilkan yang lain. Dia melakukannya dan kemudian, tanpa masalah bisa menggesek ke halaman berikutnya.

Semoga membantu seseorang.

K20
sumber
0

Gunakan // Buat boolean ini untuk mengambil data private boolean isViewShown = false;

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (getView() != null) {
        isViewShown = true;
        // fetchdata() contains logic to show data when page is selected mostly asynctask to fill the data
        fetchData();
    } else {
        isViewShown = false;
    }
} 
Rohit Sharma
sumber