ViewPager içeriği yeniden çizmiyor, boş kalıyor / boş kalıyor


86

Burada ViewPager ile ilgili çok garip bir sorun yaşıyoruz. Listeleri her ViewPager sayfasına gömüyoruz ve liste verilerini güncellerken hem liste bağdaştırıcısında hem de görünüm sayfalayıcı bağdaştırıcısında notifyDataSetChanged öğesini tetikliyoruz.

Gözlemlediğimiz şey, sayfanın bazen görünüm ağacını güncellemediği, yani boş kaldığı, hatta bazen sayfalandığında kaybolduğu. Birkaç kez ileri geri sayfalandığında, içerik aniden yeniden görünecektir. Görünüşe göre Android burada bir görünüm güncellemesini kaçırıyor. Hiyerarşi görüntüleyicisiyle hata ayıklarken, görünüşe göre hiyerarşi görüntüleyicisinin seçilen görünümü kendini yeniden çizmeye zorlaması nedeniyle bir görünüm seçmenin her zaman yeniden görünmesini sağlayacağını da fark ettim.

Yine de bunun programlı olarak çalışmasını sağlayamadım; liste görünümünü veya hatta tüm görünüm çağrı cihazını geçersiz kılmanın hiçbir etkisi olmadı.

Bu, uyumluluk-v4_r7 kitaplığı ile. Ayrıca, çağrı cihazını görüntüleme ile ilgili birçok sorunu çözdüğünü iddia ettiği için en son revizyonu kullanmayı denedim, ancak işleri daha da kötüleştirdi (örneğin, hareketler bazen artık tüm sayfalarda sayfama izin vermeyecek şekilde kırıldı.)

Bu sorunlarla başka biri de karşılaşıyor mu veya buna neyin sebep olabileceğine dair bir fikriniz var mı?

Yanıtlar:


44

Sonunda bir çözüm bulmayı başardık. Görünüşe göre uygulamamız iki sorundan muzdaripti:

  1. adaptörümüz içindeki görünümü kaldırmadı destroyItem() .
  2. Görünümleri önbelleğe alıyorduk, böylece düzenimizi yalnızca bir kez şişirmemiz gerekiyordu ve görünümü içinde kaldırmadığımız için destroyItem(), onu eklemiyorduk, instantiateItem()yalnızca mevcut konuma karşılık gelen önbelleğe alınmış görünümü döndürüyorduk.

Kaynak koduna çok derinlemesine bakmadım ViewPager- ve bunu yapmanız gerektiği tam olarak açık değil - ancak dokümanlar şöyle diyor:

destroyItem ()
Verilen konum için bir sayfa kaldır. Bağdaştırıcı, görünümü kapsayıcısından kaldırmakla sorumludur, ancak bunun yalnızca finishUpdate'ten (ViewGroup) döndüğünde yapılmasını sağlamalıdır.

ve:

Çok basit bir PagerAdapter, sayfa Görünümlerini anahtar nesneler olarak kullanmayı seçebilir, bunları oluşturduktan ve bunları üst ViewGroup'a ekledikten sonra instantiateItem'den (ViewGroup, int) döndürür. Eşleşen bir destroyItem (ViewGroup, int, Object) uygulaması, View'u ana ViewGroup'tan kaldırır ve isViewFromObject (View, Object), return view == nesnesi; olarak uygulanabilir.

Benim sonuç olduğunu Böylece ViewPageraçıkça eklemek / kendi çocukları kaldırmak için altında yatan adaptör dayanır instantiateItem()/ ' destroyItem(). Yani, adaptörünüz bir alt sınıfsaPagerAdapter , alt sınıfınız bu mantığı uygulamalıdır.

Yan not: dikkat bu içeride listeleri kullanmak durumunda ViewPager.


2
Benim için onDestroy'u işleyen FragmentPagerAdapter ile aynı sorunu yaşıyorum. Buradaki diğer çözümlerin hiçbiri de işe yaramıyor.
Greg Ennis

14
Sorun da birisinin GetChildFragmentManager yerine getFragmentManger kullanması olabilir
Boy

@Boy GetChildFragmentManager nedir?
delikte yangın

1
@Boy Wooooow .... Neden güncelleyecek bir şey bulamadığımı anlamaya çalışırken iki gün boyunca saçlarımı çekip çıkardım. TEŞEKKÜR EDERİM! (gerçekten, gerçekten çocuk yöneticisini kullanmak için Google'ın belgelerine bir bildirim koymaları gerekir, bu tamamen farklı bir yöneticiye ihtiyacınız olduğu anlamına gelmez).
user0721090601

@futtetennista Ben de aynısını yapıyorum .. bu sorunla karşılaşıyorum .. kontrol edebilir misin .. stackoverflow.com/questions/61727835/…
AskQ

55

Eğer, ViewPagerbir Parçanın içinde bir ile ayarlanmışsa , parametrenizi başlatmak için parametre olarak yerine FragmentPagerAdapterkullanın .getChildFragmentManager()getSupportFragmentManager()FragmentPagerAdapter

mAdapter = new MyFragmentPagerAdapter(getChildFragmentManager());

Onun yerine

mAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());

2
İyi yakaladım, FragmentPagerAdapter
Tobliug

1
Teşekkürler - bu işe yaradı. Ben zorlamak için çalışıyordu getItem()bir üzerinde FragmentPagerAdapterbir yeniden Fragment iç içe edildi.
kosiara - Bartosz Kosarzycki

vay bu iş cazibesi gibi. Sanırım sorun, görüntüleyicinin bir parçadaki şişirilmesinden kaynaklanıyor
Thecarisma

Böyle zamanlarda Keşke Medium gibi alkışlar olsaydı, bu yüzden size 1000'den fazla alkış verebilirdim. İyi iş, kabul edilen cevap bu olmalı
Codelicious

21

Ben de tamamen aynı problemi yaşadım ama aslında destroyItem'deki görüşü yok ettim (düşündüm). Ancak sorun, onu kullanarak imha viewPager.removeViewAt(index);etmemdi.viewPager.removeView((View) object);

Yanlış:

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

Sağ:

@Override
public void destroyItem(ViewGroup viewPager, int position, Object object) {
    viewPager.removeView((View) object);
}

İpucu için teşekkürler. Bir süredir konuyu araştırıyorum.
Moritz

2
Bu benim için çalıştı, ama ilkinin neden bir sorun olduğunu biliyor musunuz?
HannahMitt

@HannahMitt removeViewAt, ViewPager'ın geçerli alt listesi içindeki belirli konumdaki görünümü kaldırır ve sayfalar ViewPager'a herhangi bir sırayla eklenebilir (bu nedenle sayfa 0 aslında ViewPager'da dizin 1'de veya her neyse olabilir). removeView alt öğe listesini yineler ve tam olarak belirtilen nesneyi kaldırır.

2
Benim için çalışmıyor: Görünüm parçaya aktarılamıyor. Buradaki nesne bir parça.
FRK

görüntüleyici statik olmalı?
Kanagalingam

10

ViewPager, öğeleri yeniden kullanma konusunda zekice şeyler yapmaya çalışır, ancak işler değiştiğinde yeni öğe konumlarına geri dönmenizi gerektirir. Bunu PagerAdapter'ınıza eklemeyi deneyin:

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

Temel olarak ViewPager'a her şeyin değiştiğini söyler (ve onu her şeyi yeniden başlatmaya zorlar). Aklıma gelen tek şey bu.


1
Evet, bu başlıkta bu seçeneği okudum: stackoverflow.com/questions/7263291/… - ancak bu balyoz yaklaşımı gibi görünüyor. Elbette daha zarif bir yol olmalı? Listeleri çağrı cihazı sayfaları olarak kullanmakla ilgili olup olmadığını merak ediyorum.
Matthias

Bu biraz balyoz yaklaşımı, ancak bundan geri dönebilirsiniz. yani yöntemden doğru bir değer döndürmek.
Chris Banes

@ChrisBanes Dediğin gibi return POSITION_NONE;, forces it to re-instantiate everythingama benim durumumda her şeyi yeniden örneklemek istemiyorum , bu yüzden viewmevcut şeyleri temizlemeden kaldırmak mümkün olur mu? Lütfen bana bildirin
Ritesh Adulkar

sen hayat
kokususun

2

Çok fazla çözüm denedim ama beklenmedik bir şekilde viewPager.post()çalıştı

 mAdapter = new NewsVPAdapter(getContext(), articles);
    viewPager.post(new Runnable() {
        @Override
        public void run() {
            viewPager.setAdapter(mAdapter);
        }
    });

1
Tanrım. neden kimse buna olumlu oy vermedi? Bir parçaya tekrar girdiğimde ve içindeki görüntüleyici kendisini oluşturmadığında tuhaf davranışlar yaşadım ve bu şekilde biraz geciktirmek aslında sorunu çözdü!
Fugogugo

0

Android Destek Kitaplığı, her sayfada ListView olan bir ViewPager içeren bir demo Etkinliğine sahiptir. Muhtemelen bir bakmalı ve ne işe yaradığını görmelisiniz.

Eclipse'de (Android Geliştirme Araçları r20 ile):

  1. Seçiniz New > Android Sample Project
  2. Hedef API seviyenizi seçin (mevcut olan en yenisini öneririm)
  3. Seçiniz Support4Demos
  4. Projeye sağ tıklayın ve seçin Android Tools > Add Support Library
  5. Uygulamayı çalıştırın ve seçin Fragmentve ardındanPager

Bunun kodu girildi src/com.example.android.supportv4.app/FragmentPagerSupport.java. İyi şanslar!


teşekkürler - Şuna bir bakacağım! Belki yanlış yaptığımız bir şeyi fark edeceğim.
Matthias

0

Bununla karşılaştım ve çok benzer sorunlar yaşadım. Hatta bunu sordumYığın taşması konusunda .

Benim için, benim görüşümün ebeveyninin ebeveyninde , birisi aramadan alt sınıflara girdi LinearLayoutve geçersiz kıldı . Bu önlendi verequestLayout()super.requestLayout()onMeasureonLayout ViewPager'ımda çağrılmadı (hierarchyviewer bunları manuel olarak çağırsa da). Ölçülmeden, ViewPager'da boş görüneceklerdir.

Öyleyse kapsayıcı görünümlerinizi kontrol edin. View'dan alt sınıflara ayırdıklarından ve requestLayout veya benzeri bir şeyi körü körüne geçersiz kılmadıklarından emin olun.


0

Aynı sorunu yaşadım, bununla ilgili bir şey var ListView(çünkü liste boşsa boş görünümüm iyi görünüyor). Sadece denilen requestLayout()problemleri üzerinde ListView. Şimdi iyi çiziyor!


0

ViewPager ve FragmentStatePagerAdapter kullanırken aynı problemle karşılaştım. Validate () ve requestLayout () 'u çağırmak için 3 saniyelik gecikmeli bir işleyici kullanmayı denedim ama işe yaramadı. ViewPager'ın arka plan rengini aşağıdaki gibi sıfırlamak ne işe yaradı:

MyFragment.java

    private Handler mHandler;
    private Runnable mBugUpdater;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = new ViewPager(getActivity());
        //...Create your adapter and set it here...

        mHandler = new Handler();
        mBugUpdater = new Runnable(){
            @Override
            public void run() {
                mVp.setBackgroundColor(mItem.getBackgroundColor());
                mHandler = null;
                mBugUpdater = null;
            }           
        };
        mHandler.postDelayed(mBugUpdater,50);

        return rootView;
    }

    @Override
    public void onPause() {
        if(mHandler != null){
            //Remove the callback if it hasn't triggered yet
            mHandler.removeCallbacks(mBugUpdater);
            mHandler = null;
            mBugUpdater = null;
        }
        super.onPause();
     }

0

Aynı semptomlarla ilgili bir sorun yaşadım, ancak benim açımdan aptalca bir hata olduğu ortaya çıkan farklı bir neden. Birine yardımcı olur diye buraya eklemeyi düşündüm.

Önceden iki parçaya sahip olan FragmentStatePagerAdapter kullanan bir ViewPager'ım vardı, ancak daha sonra bir üçüncü ekledim. Bununla birlikte, varsayılan ekran dışı sayfa sınırının 1 olduğunu unuttum - bu nedenle, yeni üçüncü parçaya geçersem, ilki yok edilir ve sonra geri döndükten sonra yeniden oluşturulur. Sorun şu ki, faaliyetim bu parçaları UI durumlarını başlatmak için bilgilendirmekten sorumluydu. Bu, etkinlik ve parça yaşam döngüleri aynı olduğunda işe yaradı, ancak düzeltmek için, başlangıç ​​yaşam döngüleri sırasında kendi UI'larını başlatmak için parçaları değiştirmem gerekiyordu. Sonunda setOffscreenPageLimit'i 2 olarak değiştirdim, böylece üç parçanın her biri her zaman canlı tutuldu (bu durumda çok bellek yoğun olmadıkları için güvenlidir).


-1

Benzer bir sorun yaşadım. Görünümleri önbelleğe alıyorum çünkü içinde yalnızca 3 görünüme ihtiyacım var ViewPager. İleri kaydırdığımda her şey yolunda ama geriye doğru kaymaya başladığımda hata oluşuyor, "Benim görüşümde zaten bir ebeveyn var" diyor. Çözüm, gereksiz öğeleri manuel olarak silmektir.

@Override
    public Object instantiateItem(ViewGroup container, int position) {
        int localPos = position % SIZE;
        TouchImageView view;
        if (touchImageViews[localPos] != null) {
            view = touchImageViews[localPos];
        } else {
            view = new TouchImageView(container.getContext());
            view.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
            touchImageViews[localPos] = view;
        }
        view.setImageDrawable(mDataModel.getPhoto(position));
        Log.i(IRViewPagerAdpt.class.toString(), "Add view " + view.toString() + " at pos: " + position + " " + localPos);
        if (view.getParent() == null) {
        ((ViewPager) container).addView(view);
    }
        return view;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object view) {
        //      ((ViewPager) container).removeView((View) view);
        Log.i(IRViewPagerAdpt.class.toString(), "remove view " + view.toString() + " at pos: " + position);
    }

..................

private static final int SIZE = 3;
private TouchImageView[] touchImageViews = new TouchImageView[SIZE];

-1

Benim için sorun, uygulama işlemi sonlandırıldıktan sonra etkinliğe geri dönmekti. Android kaynaklarından değiştirilmiş özel bir görünüm çağrı cihazı bağdaştırıcısı kullanıyorum. Görünüm çağrı cihazı doğrudan etkinliğin içine yerleştirilmiştir.

Aranıyor viewPager.setCurrentItem(position, true);

(animasyonla) verileri ayarladıktan ve notifyDataSetChanged () çalıştıktan sonra çalışıyor gibi görünüyor, ancak parametre false olarak ayarlanmışsa çalışmıyor ve parça boş. Bu, birine yardımcı olabilecek uç bir durumdur.


-1

Kotlin kullanıcıları için:

Parçalarınızda; Yerine childFragmentManagerkullanınviewPagerAdapter

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.