ViewPager.setOffscreenPageLimit (0) beklendiği gibi çalışmıyor


100

Örneğimde kullandığım parçalar ViewPageroldukça yoğun kaynaklıdır, bu yüzden bir seferde yalnızca bir tane yüklemek istiyorum. Aşağıdakileri denediğimde:

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

Benim FragmentStatePagerAdapter.getItem(int position)geçersiz kılma fonksiyonum 3 kez çağrılıyor, bu da aradığımda oluyor mViewPager.setOffscreenPageLimit(1). 0 ekran dışı sayfa belirlediğim için yalnızca bir kez çağrılmasını beklerdim.

Ben dersen çünkü her şeyi doğru arıyorum inan mViewPager.setOffscreenPageLimit(2), FragmentStatePagerAdapter.getItem(int position)ben beklediğiniz gibi 5 kez denir.

ViewPager en az 1 ekran dışı sayfa mı gerektiriyor yoksa burada yanlış bir şey mi yapıyorum?


9
Bir özellik isteği ekledim: code.google.com/p/android/issues/detail?id=56667
Mark


Yalnızca 3 sekmem vardı ve ayar ViewPager.setOffscreenPageLimit(2)benim için çalıştı. TryViewPager.setOffscreenPageLimit(totTabs - 1)
sibin

Yanıtlar:


112

ViewPager en az 1 ekran dışı sayfa gerektirir mi

Evet. Kaynak kodunu doğru okuyorsam, LogCat'te bununla ilgili aşağıdaki gibi bir uyarı almalısınız:

Requested offscreen page limit 0 too small; defaulting to 1

6
Bu bir çözüm değil! 2 değil sadece 1 parça yüklemek istiyorum. Bu bir şekilde mümkün olabilir mi?
HGPB

14
@Haraldo: "Bu bir şekilde mümkün mü?" - ile değil ViewPager. ViewPagerbu parçaları, görünümlerin var olması için oluşturur, böylece kullanıcı bunlar arasında geçiş yapabilir, animasyonlu efekt eski görünümü ekrandan kayarken gösterir ve yeni görünüm ekrana kayar. Var olmayan ViewPagerşeyler arasında geçiş yapabilen kendi yazınızı yazmaya çalışabilirsiniz.
Bununla

2
Evet, bu konuyu okudum. Mantıklı değil. setOffscreenPageLimit(0)0 yapabilmeyi bekliyorum. Sonra sonuçları kendim halledebilirim. Varsayılan boş bir parça, örneğin bir parçası yüklenene kadar bir yer tutucu olabilir. Bunların tümü UI iş parçacığının dışında gerçekleşebilir. Her neyse, pek düşünmedim.
HGPB

5
@Haraldo: "Varsayılan boş bir parça, örneğin parçalar yüklenene kadar bir yer tutucu olabilir" - bugün parçanızın mevcut uygulamasıyla, mevcut ViewPagerolduğunda gerçek içerikle değiştirebileceğiniz bir yer tutucuya sahip olabilirsiniz. .
CommonsWare

2
onPageChangeListener çözüm gibi görünüyor.
alicanbatur

123

Bulduğum en iyi yol setUserVisibleHint
bunu parçanıza eklemekti

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) {
        // load data here
    }else{
       // fragment is no longer visible
    }
}

1
Bu çözüm için +++++ !!! teşekkürler, bu kodu ekledikten sonra ilk defa NPL aldım, sadece try catch bloğunu ekledim ve çalışmaları benim için mükemmel !!!
Bhavin Chauhan

1
Bunu kullandığınızda, tarihi secondViewPager Parçasına, ikinci parçaya üçüncü parçanın yükleme verilerini yüklemez. Biri bana yardım edebilir mi?
Arshad

Eksik bir şey mi var, onCreateView'den önce çağrılan setUserVisibleHint
Anton Makov

1
En iyi çözüm artık kullanımdan kaldırıldı
M.Sameer

@ M.Sameer setUserVisibleHint için herhangi bir alternatif yanlış mı?
Yudi karma

8

Şöyle deneyebilirsiniz:

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(){}

bu en iyi cevap!
Radesh

7

İlk Ekle

   boolean isFragmentLoaded = false;

-den

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

        isFragmentLoaded = true;
    }
else{
     }
}

7
ancak bu yöntem onCreateView'den önce çağrı yapar
AndroidGeek

2

ViewPager, setOffscreenPageLimit (0) ile değiştiremeyeceğiniz sonraki sayfayı (Parça) yüklemek için varsayılandır. Ama hacklemek için bir şeyler yapabilirsiniz. ViewPager'ı içeren Activity'de onPageSelected işlevini uygulayabilirsiniz. Sonraki Fragment'te (yüklemek istemediğiniz), bir fonksiyon yazarsınız, diyelim ki showViewContent () burada tüm kaynak tüketen init kodunu yerleştirirsiniz ve onResume () yönteminden önce hiçbir şey yapmazsınız. Ardından onPageSelected içinde showViewContent () işlevini çağırın. Umarım bu yardımcı olur.


1

bu eski iş parçacığı olabilir ama bu benim için çalışıyor gibi görünüyor. Bu işlevi geçersiz kılın:

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

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

mutlu kodlamalar ...


web görünümünde neler var? Bunun için yeni bir konu oluşturmanızı öneririm.
ralphgabb

1

benim durumumda görünümlerde bazı animasyonlar başlatmak istedim, ancak setUserVisibleHint ile bazı sorunlar var ...
benim çözümüm:

Adaptörünüz için 1 / addOnPageChangeListener:

mViewPager.addOnPageChangeListener(this);

2 / OnPageChangeListener uygulamak:

public class PagesFragment extends Fragment implements ViewPager.OnPageChangeListener

3/3 yöntemi geçersiz kılın:

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

}

@Override
public void onPageSelected(int position)
{ 
}

@Override
public void onPageScrollStateChanged(int state)
{
}

4 / bu değişkeni sınıfınızda beyan edin ve başlatın

private static int mTabState = 1;

not : bağdaştırıcımda üç parçam var ve setCurrentItem için mTabState kullanıyorum ve hangi parçanın kullanıcıya zamanında gösterildiğini algılayan bağdaştırıcının geçerli konumu ... 5 / in onPageSelected yöntemi bu kodları ekleyin:

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

önceki sayfa veya mevcut sayfa sayfa 0 ise (0 konumundaki parça), o zaman bunları yapın

6 / şimdi parça sınıfınızda (adaptörün 0 konumundaki parça), yayın alıcısı oluşturmalı ve onResume yöntemine kaydetmeli ve onu Duraklatma yöntemi:

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

Özet: Parça Çağrı Bağdaştırıcım var, içinde Üç Parça gösteriyor, Adaptörün 0 Konumundaki Parçadaki Görünümlerde bazı Animasyonlar göstermek istiyorum, Bunun için BroadcastReceiver kullanıyorum. Parça Seçildiğinde Animasyon yöntemini başlatıyorum ve Kullanıcıya Görüntülemeleri gösteriyor, Parça Kullanıcıya Gösterilmediğinde Görünmez Görüntülere çalışıyorum ...


1

Viewpager'da görünümü yenileme sorununu çözmek için Lütfen Bu Kodu Deneyin ...

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

0

"instantiateItem" işlevi için, sadece parçayı hazırlayın, ancak ağır içeriği yüklemeyin.

"OnPageChangeListener" kullanın, böylece belirli bir sayfaya her gittiğinizde ağır içeriğini yüklersiniz ve gösterirsiniz.


0

Bende de aynı sorun var. Bu sitede bazı yararlı kodlar buldum ve onu dönüştürdüm.

MViewPager.setOffscreenPageLimit (...) için min int; 1'dir, yani 0 olarak değiştirseniz bile 2 sayfanız yüklü olacaktır.

Yapılması gereken ilk şey, statik bir int oluşturmaktır, maxPageCount'u çağıracağız ve FragmentStatePagerAdapter yöntemini geçersiz kılarak maxPageCount'u döndürmek için getCount () değerini geçersiz kılacağız:

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

Ardından, programın herhangi bir yerinden erişilebilen ve bu maxCount'u değiştirmenize izin verecek statik bir yöntem oluşturun:

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

Şimdi maxPageCount'u 1 olarak başlatın. İstediğiniz zaman başka bir sayfa ekleyebilirsiniz. Benim durumumda, kullanıcının mevcut sayfayı önce diğerini oluşturmadan önce işlemesini istediğimde. Bunu yapar ve sonra sorunsuz bir şekilde sonraki sayfaya geçebilir.

Umarım birine yardımcı olur.


0

Bunu kullanın // veriyi almak için boole oluştur özel boole 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;
    }
} 
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.