ViewPager dinamik olarak güncellenir mi?


316

ViewPager içindeki içeriği güncelleyemiyorum.

FragmentPagerAdapter sınıfında instantiateItem () ve getItem () yöntemlerinin doğru kullanımı nedir?

Parçalarımı başlatmak ve döndürmek için yalnızca getItem () kullanıyordum:

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

Bu iyi çalıştı. Ancak içeriği değiştiremiyorum.

Bu yüzden buldum: ViewPager PagerAdapter Görünümü güncellemiyor

"Benim yaklaşımım instantiateItem () yöntemindeki herhangi bir örneklenmiş görünüm için setTag () yöntemini kullanmaktır"

Şimdi bunu yapmak için instantiateItem () uygulamak istiyorum. Ama ne dönmek zorundayım (türü Object) ve getItem (int pozisyon) ile ilişkisi nedir?

Referansı okudum :

  • public abstract Fragment getItem (int konum)

    Belirtilen bir konumla ilişkili Parçayı döndürün.

  • public Object instantiateItem (ViewGroup kapsayıcısı, int konumu)

    Verilen konum için sayfa oluşturun. Bağdaştırıcı, görünümü burada verilen kapsayıcıya eklemekten sorumludur, ancak bunun yalnızca finishUpdate'den (ViewGroup) döndüğü zaman yapılmasını sağlamalıdır. Parametreler

    container Sayfanın gösterileceği İçeren Görünüm. konum Örneklenecek sayfa konumu.

    İadeler

    Yeni sayfayı temsil eden bir Nesne döndürür. Bunun bir Görünüm olması gerekmez, ancak sayfanın başka bir kabı olabilir.

ama hala anlamıyorum.

İşte kodum. Destek paketi v4 kullanıyorum.

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

İşte benzer bir sorunu olan biri, cevap yok http://www.mail-archive.com/android-developers@googlegroups.com/msg200477.html


İlgili bileşenleri daha iyi anlamak için, ayrı arka navigasyon geçmişine sahip sekmeli bir ViewPager hakkındaki eğiticimi okumak yardımcı olabilir. GitHub ve ek kaynaklar üzerinde çalışan bir örnekle birlikte gelir: medium.com/@nilan/…
marktani


Bu örneği GitHub'da kontrol edebilirsiniz . Umarım bu örnek size yardımcı olur.
Cabezas

İyi basit çözüm: stackoverflow.com/a/35450575/2162226
Gene Bo

Google kısa süre önce dinamik Parça / Görünüm güncellemelerini basitleştiren ViewPager2'yi tanıttı. Örnekleri github.com/googlesamples/android-viewpager2 adresinde veya bu cevabı stackoverflow.com/a/57393414/1333448
Yves

Yanıtlar:


605

FragmentPagerAdapter veya FragmentStatePagerAdapter kullanırken, en iyisi sadece ele almak getItem()ve dokunmamaktır instantiateItem(). instantiateItem()- destroyItem()- isViewFromObject()PagerAdapter arayüz FragmentPagerAdapter kullandığı çok daha basit uygulamaya bir alt seviye arayüz getItem()arayüz.

Buna girmeden önce açıklığa kavuşturmalıyım

görüntülenen gerçek parçaları kapatmak isterseniz, FragmentPagerAdapter kullanmaktan kaçınmanız ve FragmentStatePagerAdapter kullanmanız gerekir.

Bu cevabın önceki bir sürümü, örneği için FragmentPagerAdapter kullanma hatasını yaptı - bu işe yaramaz çünkü FragmentPagerAdapter ilk kez gösterildikten sonra hiçbir zaman bir parçayı yok etmez.

Bağladığınız gönderide sağlanan setTag()ve findViewWithTag()geçici çözümü önermiyorum . Bildiğiniz gibi, parçaları kullanmak setTag()ve findViewWithTag()parçalarla çalışmaz, bu yüzden iyi bir eşleşme değildir.

Doğru çözüm geçersiz kılmaktır getItemPosition(). Ne zaman notifyDataSetChanged()denir, ViewPager çağıran getItemPosition()onlar farklı bir konuma taşınması veya kaldırılması gerekip gerekmediğini görmek için kendi adaptörü içindeki tüm öğeleri.

Varsayılan olarak, getItemPosition()getiri POSITION_UNCHANGED, araçlar, "Bu nesne yok etmek veya kaldırmak değil, olduğu gayet iyi." Geri dönmek POSITION_NONE, "Bu nesne artık görüntülemekte olduğum bir öğe değil, kaldırın" diyerek sorunu giderir. Dolayısıyla, bağdaştırıcınızdaki her bir öğeyi kaldırma ve yeniden oluşturma etkisi vardır.

Bu tamamen meşru bir çözüm! Bu düzeltme, dataSetChanged öğesinin görünüm geri dönüşümü olmadan normal bir Bağdaştırıcı gibi davranmasını sağlar. Bu düzeltmeyi uygularsanız ve performans tatmin ediciyse, yarışlara gidersiniz. İş bitmiş.

Daha iyi bir performansa ihtiyacınız varsa daha ince bir getItemPosition()uygulama kullanabilirsiniz . Aşağıda, bir dize listesinden parça oluşturan bir çağrı cihazına bir örnek verilmiştir:

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

Bu uygulama ile, yalnızca yeni başlıkları gösteren parçalar görüntülenecektir. Hala listede bulunan başlıkları gösteren herhangi bir parça, listedeki yeni konumlarına taşınacak ve artık listede bulunmayan başlıkları olan parçalar yok edilecektir.

Parçanın yeniden oluşturulmamış olmasına rağmen yine de güncellenmesi gerekiyorsa ne olur? Canlı bir parçadaki güncellemeler, parçanın kendisi tarafından en iyi şekilde ele alınır. Sonuçta, bir parçaya sahip olmanın avantajı - bu kendi denetleyicisidir. Bir parça, içindeki başka bir nesneye bir dinleyici veya gözlemci ekleyebilir onCreate()ve sonra onu kaldırabilir onDestroy(), böylece güncellemelerin kendisini yönetebilir. getItem()ListView veya diğer AdapterView türleri için bir bağdaştırıcıya yaptığınız gibi tüm güncelleştirme kodunu içine koymak zorunda değilsiniz .

Son bir şey - FragmentPagerAdapter'ın bir parçayı yok etmemesi, getItemPosition'ın bir FragmentPagerAdapter içinde tamamen işe yaramadığı anlamına gelmez. ViewPager'de parçalarınızı yeniden sıralamak için bu geri aramayı kullanmaya devam edebilirsiniz. Yine de onları asla FragmentManager'dan tamamen kaldırmaz.


4
Çalışmıyor, hala hiçbir şey güncellenmiyor ... kodumu gönderdi.
Ixx

64
Tamam, sorunu çözdüm - FragmentPagerAdapter yerine FragmentStatePagerAdapter kullanmanız gerekiyor. FragmentPagerAdapter hiçbir zaman FragmentManager'dan parçaları kaldırmaz, sadece onları ayırır ve ekler. Daha fazla bilgi için dokümanları kontrol edin - genel olarak yalnızca kalıcı olan parçalar için FragmentPagerAdapter kullanmak istersiniz. Düzeltmeyle örneğimi düzenledim.
Bill Phillips

1
Bunu bir süre sonra inceleyeceğim ... Cevabınız için teşekkürler. Ve sonra işe yararsa cevabınızı kabul ediyorum. Son yorumunuzdan önce her seferinde yeni bir ViewPager kaldırmak ve eklemek için uyguladım ve bu işe yarıyor. Çok iyi bir çözüm değil, ama şimdi değiştirmek için zamanım yok.
Ixx

12
Haklısın, adaptörün sınıfını FragmentStatePagerAdapter olarak değiştirmek tüm sorunumu çözdü. Teşekkürler!
Ixx

2
POSITION_NONE öğesini döndürdüğümde bile, kullanırken parçamın FragmentStatePagerAdapterkaldırıldığını ve yeni örneği oluşturduğunu görebiliyorum. Ancak yeni örnek, eski bir parçanın durumuyla birlikte bir saveInstanceState Paketi alır. Parçayı nasıl tamamen yok edebilirim, böylece tekrar oluşturulduğunda Bundle null olur?
Singed

142

Bunun yerine geri dönme POSITION_NONEgelen getItemPosition()ve tam görünüm rekreasyon neden bunu:

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

Parçalarınız UpdateableFragmentarabirimi uygulamalıdır :

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

ve arayüz:

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

Veri sınıfınız:

public class UpdateData {
    //whatever you want here
}

1
Bu MainActivity de arayüzü uygulamak gerektiği anlamına mı geliyor ??? Lütfen bana yardım et. Mevcut uygulamada, MainActivity sınıfımı parçalar arasında bir iletişimci olarak kullanıyorum, bu yüzden bu çözüm hakkında kafam karıştı.
Rakeeb Rajbhandari

1
Tamam Fragmentdinamik bir şekilde güncellediğim tam bir uygulama ile başka bir yerde cevap verdim , bir göz atın: stackoverflow.com/questions/19891828/…
M-WaJeEh 20:13

@ M-WaJeEh belki bazı örnek lütfen !!! şehirlerin listesi ile bir listview var ve şehir seçtikten sonra bu şehir hakkında bilgi ile viewpager (3 sayfa) açar. Tamam çalışıyor. ancak başka bir şehir görüntüleyicisi seçildikten sonra yalnızca 3. d page on refreshes the 1-st page only after swiping pages? thw 2sayfa her zaman boş görünür . teşekkürler
SERG

4
çalışma hayatımın son 2,5 günü boyunca gördüğüm tüm şeyler arasında .. bu benim için işe yarayan tek şey .. her türlü arigato, teşekkürler, spaciba, sukran .. n.
Orkun Ozen

2
Ejderhaların Annesi !, bu bir cazibe gibi çalışıyor, tek çözüm benim için çalıştı ... çok teşekkürler !!
Sebastián Guerrero

24

ViewPager7 parçalı bir tane olduğunda daha önce karşılaştığım aynı problemle karşı karşıya olanlar için . İngilizce içeriği APIhizmetten yüklemek için bu fragmanlar için varsayılan ama burada ayarları faaliyetten dil değiştirmek istiyorum ve ayarları bitirdikten sonra ViewPagerana aktivite ben dilden kullanıcı ve dil seçimini eşleştirmek için parçaları yenilemek istiyorum kullanıcı burada ilk kez çalışmak için ne yaptım Arapça seçerse Arapça içerik

1- Yukarıda belirtildiği gibi FragmentStatePagerAdapter kullanmalısınız.

2- mainActivity'de onResume'u geçersiz kıldım ve aşağıdakileri yaptım

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

3-i getItemPosition()mPagerAdapter içinde geçersiz kıldı ve geri dönmesini sağlayın POSITION_NONE.

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

çekicilik gibi çalışır


1
Bir durum dışında çalışır. ViewPager içindeki son öğeyi sildiğinizde. Sonra listeden kaldırılmaz.
Vlado Pandžić

Viewpager'daki geçerli parçanın hem sol hem de sağ tarafına dinamik olarak parçalar ekliyordum. Bu işe yaradı! Teşekkürler.
h8pathak

15

Bu sorunla karşılaştım ve sonunda bugün çözdüm, bu yüzden öğrendiklerimi yazdım ve umarım Android'lerde yeni olan ViewPagerve yaptığım gibi güncelleme yapan biri için yararlı olur . Ben kullanıyorum FragmentStatePagerAdapterAPI düzeyinde 17 ve şu anda sadece 2 parçaları var. Bence doğru olmayan bir şey olmalı, lütfen beni düzeltin, teşekkürler. resim açıklamasını buraya girin

  1. Seri veri belleğe yüklenmelidir. Bu bir CursorLoader/ AsyncTask/ kullanılarak yapılabilir Thread. Otomatik olarak yüklenip yüklenmeyeceği kodunuza bağlıdır. A kullanıyorsanız CursorLoader, kayıtlı bir veri gözlemcisi olduğundan otomatik olarak yüklenir.

  2. Aradıktan sonra viewpager.setAdapter(pageradapter), bağdaştırıcılar getCount()sürekli olarak parça oluşturmak için çağrılır. Veriler yükleniyorsa, getCount()0 değerini döndürebilir, böylece gösterilen hiçbir veri için sahte parçalar oluşturmanıza gerek yoktur.

  3. Veri yüklendikten sonra, bağdaştırıcı getCount()hala 0 olduğundan otomatik olarak fragman oluşturmaz , bu nedenle döndürülecek gerçek yüklü veri numarasını ayarlayabilir ve getCount()ardından bağdaştırıcıyı arayabiliriz notifyDataSetChanged(). ViewPagerbellekteki verilerle parçalar oluşturmaya başlar (sadece ilk 2 parça). Geri dönmeden önce yapılır notifyDataSetChanged(). Sonra ViewPagerihtiyacınız olan doğru parçaları vardır.

  4. Veritabanındaki ve bellekteki veriler güncellenirse (üzerinden yazılır) veya yalnızca bellekteki veriler güncelleştirilirse (geri yazılır) veya yalnızca veritabanındaki veriler güncelleştirilirse. Son iki durumda veri otomatik olarak veritabanından belleğe yüklenmezse (yukarıda belirtildiği gibi). ViewPagerVe çağrı cihazı adaptörü sadece bellekte verilerle başa.

  5. Bu yüzden bellekteki veriler güncellendiğinde, sadece adaptörleri çağırmamız gerekir notifyDataSetChanged(). Parça zaten oluşturulduğundan, bağdaştırıcılar döndürülmeden onItemPosition()önce çağrılır notifyDataSetChanged(). Yapılması gereken bir şey yok getItemPosition(). Ardından veriler güncellenir.


(memeory) veri güncelledikten sonra yapmanız gereken bir şey notifyDataSetChanged()bulmadım , sadece çağrı sonra sadece otomatik olarak güncellenir, çünkü kullandığım parça (chartview ile) kendini yenileyecektir. değilse, statik bir parça gibi, ben aramak zorunda olacak onItemPositon()ve POSITION_NONE bunun için üzgünüm dönecek
oscarthecat

Bu diyagramı yapmak için hangi aracın kullanıldığına dair bir fikri olan var mı?
JuiCe

12

destroyDrawingCache()Sonra notifyDataSetChanged()kodunuzda ViewPager deneyin .


3
Burada aynı. Harika çalışıyor teşekkürler. Özellikle zor zaman geçirdim çünkü Fragmentsgörüşme cihazımda kullanmıyorum . Çok teşekkür ederim!
Seth

11

Hayal kırıklığı saat bu sorunun üstesinden gelmek için her şeyden çözümler çalışıyor ve aynı zamanda gibi diğer benzer sorular üzerine birçok çözümler çalışırken sonra bu , bu ve bu tüm bu sorunu çözmek için ve yapmak benimle BAŞARISIZ hangi ViewPagereski yok etmek Fragmentve dolgu pagerile yeni Fragments. Sorunu aşağıdaki gibi çözdüm:

1) Make ViewPageruzanır için sınıfını FragmentPagerAdapteraşağıdaki gibidir:

 public class myPagerAdapter extends FragmentPagerAdapter {

2) için bir madde oluşturma ViewPagersaklamak olduğunu titleve fragmentşu şekilde:

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) aşağıdaki gibi benim saklamak ViewPageriçin benim FragmentManagerörnek almak yapıcı olun class:

private FragmentManager mFragmentManager;
private ArrayList<PagerItem> mPagerItems;

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

4) Yeni listeden yeni ayarlamayı tekrar aşağıdaki gibi yapmak için , öncekini doğrudan kendisinden adaptersilerek yeni verilerle verileri yeniden ayarlamak için bir yöntem oluşturun :fragmentfragmentManageradapterfragment

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) Kaptan Activityveya Fragmentadaptörü yeni verilerle yeniden başlatmayın. Yeni verileri yöntemle setPagerItemsyeni verilerle aşağıdaki gibi ayarlayın:

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

Umut ediyorum bu yardım eder.



bu konuda bana yardımcı olabilir misiniz stackoverflow.com/questions/41547995/…
engerek

10

Nedense hiçbir cevap benim için çalıştı, bu yüzden benim fragmentStatePagerAdapter süper çağırmadan restoreState yöntemini geçersiz kılmak zorunda kaldı. Kod:

private class MyAdapter extends FragmentStatePagerAdapter {

    // [Rest of implementation]

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

}

1
Bu SO cevabındaki diğer her şeyi denedikten sonra, bu benim için işe yaradı. Söz konusu PagerAdapter barındıran Etkinliğe dönen bir etkinliği bitirmek () ing. Bu durumda tüm parçalarımın yeniden oluşturulmasını istiyorum çünkü bitirdiğim Etkinlik parçaları çizmek için kullanılan durumu değiştirmiş olabilir.
JohnnyLambada

OMG .. işe yarıyor .. işe yarıyor .. kudos: D Benim durumumda viewpager geçerli öğe nesnesini kaldırmanız gerekiyor. ancak yukarıdaki tüm yöntemler / adımlar denendikten sonra geçerli parça güncellenmiyor.
Rahul Khurana

3

Bill Phillips tarafından sağlanan çözümü biraz benim ihtiyaçlarına göre değiştirdim

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

böylece getItemPosition()döner POSITION_NONEyalnızca şu anda bu fragmanlar için FragmentManagerzaman getItemPositionolarak adlandırılır. (Bu FragmentStatePagerve ViewPageronunla ilişkili bir Faaliyette olmayan bir Parçada bulunduğunu unutmayın)


2

Benzer bir sorunum vardı ama mevcut çözümlere (sabit kodlu etiket adları vb.) Güvenmek istemiyorum ve M-WaJeEh'in çözümünü benim için çalıştıramadım. İşte benim çözümüm:

Bir dizide getItem içinde oluşturulan parçaları referansları tutmak. Aktivite configurationChange veya bellek yetersizliği veya her ne olursa olsun (-> aktiviteye geri döndüğünde (-> aktiviteye geri döndüğünüzde) parçalanmadığı sürece iyi çalışır, 'getItem' tekrar çağrılmadan ve böylece diziyi güncellemeden parçalar son durumlarına geri döner ).

Bu sorunu önlemek için instantiateItem (ViewGroup, int) uyguladım ve dizimi şu şekilde güncelledim:

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

Yani, bir yandan benim için çalışan ve sizinle paylaşmak istediğim bir çözüm bulduğum için mutluyum, ama aynı zamanda başka birinin benzer bir şey denediğini ve neden olmamamın herhangi bir nedeni olup olmadığını sormak istedim. böyle mi yapıyorsun Şimdiye kadar benim için çok iyi çalışıyor ...


Ben de ilgili tamam şey var stackoverflow.com/a/23427215/954643 muhtemelen öğeyi kaldırmak gerektiği halde, myFragmentsiçinde public void destroyItem(ViewGroup container, int position, Object object)kuyu böylece bir bayat Fragement referansını çekmezse olarak.
qix

1

İçeriği güncellemek için EventBus kitaplığını kullanıyorum . Mantık basittir, tıpkı EventBus'un nasıl yapılacağı gibi . Örneği kontrol etmeye gerek yoktur . Kod burada:FragmentViewPagerFragmentPagerAdapter

1: Olayları tanımlayın

Güncellenmesi gereken mesajı tanımlayın.

public class UpdateCountEvent {
    public final int count;

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

2. abone hazırlayın

Güncelleme için gerekli olan parçaya aşağıdaki kodu yazın.

@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 olayları

Aşağıdaki kodu, parametreyi güncellemesi gereken diğer Activityveya diğer kodlara yazınFragment

//input update message
EventBus.getDefault().post(new UpdateCountEvent(count));

1

FragmentStatePagerAdapter kullanmak istiyorsanız, lütfen https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary% adresine göz atın. 20 Yıldızlar & groupby = & sort = & id = 37990 . FragmentStatePagerAdapter ile kullanım durumunuzu düzeltebilecek veya düzeltemeyecek sorunlar vardır.

Ayrıca, bağlantı çok az çözümleri vardır .. az sizin ihtiyacına uygun olabilir.


Bu URL'den çözüm buldum. Bu özette değiştirilmiş FragmentStatePagerAdapter kullandımKodumda gist.github.com/ypresto/8c13cb88a0973d071a64 olması gerektiği gibi çalışmaya başladı.
Rafael

Güzel. Evet. Link'in de birkaç çözümü var.
cgr

1

Aynı problemi yaşadım ve çok fazla araştırdım. Stackoverflow veya google üzerinden verilen herhangi bir cevap benim sorunum için çözüm değildi. Benim sorunum kolaydı. Bir listem var, bu listeyi viewpager ile gösteriyorum. Listenin başına yeni bir öğe eklediğimde ve viewpager nothings değiştiğinde yenilendi. Son çözümüm herkesin kullanabileceği çok kolaydı. Listeye yeni bir öğe eklendiğinde ve listeyi yenilemek istediğinizde. Önce viewpager adaptörünü null olarak ayarlayın, sonra adaptörü yeniden oluşturun ve i'yi viewpager olarak ayarlayın.

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

Bağdaştırıcınızın FragmentStatePagerAdapter öğesini uzattığından emin olun


1

İşte @Bill Phillips One'dan gelen bilgileri içeren uygulamam, verilerin değiştiği durumlar dışında çoğu zaman parçalı önbellek alıyor. Basit ve iyi çalışıyor gibi görünüyor.

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

0

Çok farklı yaklaşımlar deniyordum, hiçbiri sorunumu gerçekten çözmedi. Aşağıda, hepinizin sağladığı çözümlerin bir karışımıyla nasıl çözdüğümü aşağıda görebilirsiniz. Herkese teşekkürler.

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

Yalnızca sayfa onResume () sonra yenilemek istiyorum.

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

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

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

FragmentsMain'imde, yenilemek istediğim sayfa olup olmadığını söyleyen genel tamsayı "page" var.

public class FragmentsMain extends Fragment {

private Cursor cursor;
private static Context context;
public int page=-1;

0

Partiye geç kaldığımı biliyorum. TabLayout#setupWithViewPager(myViewPager);Hemen sonra arayarak sorunu çözdümFragmentPagerAdapter#notifyDataSetChanged();


0

Bu çözüm herkes için işe yaramaz, ancak benim durumumda, ViewPager'imdeki her Parça farklı bir sınıftır ve her seferinde sadece bir tane vardır.

Bu kısıtlama ile, bu çözüm güvenlidir ve üretimde kullanımı güvenli olmalıdır.

private void updateFragment(Item item) {

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

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

    }
}

Aynı parçanın birden çok sürümüne sahipseniz, bu parçayı, güncellemek istediğiniz parçanın olup olmadığını belirlemek için bu parçacıklardaki yöntemleri çağırmak için kullanabilirsiniz.


0

Bu birisine yardımcı olabilir - benim durumumda yeni bir sayfa eklerken, görünüm çağrı cihazı mevcut bir parçanın konumunu iki kez soruyordu, ancak yeni öğenin konumunu sormuyordu, bu da yanlış davranış ve verilerin görüntülenmemesine neden oldu.

  1. FragmentStatePagerAdapter kaynağını kopyalayın (çağlarda güncellenmemiş gibi görünüyor).

  2. NotifyDataSetChanged () geçersiz kıl

    @Override
    public void notifyDataSetChanged() {
        mFragments.clear();
        super.notifyDataSetChanged();
    }
  3. Kilitlenmeleri önlemek için destroyItem () öğesine bir sağlık kontrolü ekleyin:

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

0

Yukarıdaki tüm cevapları ve diğer bazı yazıları inceledim, ancak yine de benim için işe yarayan bir şey bulamadım (dinamik olarak sekme ekleme ve kaldırma ile birlikte farklı parça türleri ile). FWIW takip eden yaklaşım benim için işe yaradı (başkalarının aynı sorunları olması durumunda).

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

0

Parçayı dizin temelinde yeniden oluşturmak veya yeniden yüklemek istiyorsanız, FragmentPagerAdapter yerine FragmentStatePagerAdapter kullanın Örneğin Örneğin, FirstFragment dışında bir parçayı yeniden yüklemek istiyorsanız, örneği kontrol edebilir ve konumu bu şekilde döndürebilirsiniz

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

0

İnstantiateItem'in mFragments öğesinin getItemPosition öğesini değiştirmeniz gerekir.

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

Tabanlı AndroidX FragmentStatePagerAdapter.java, çünkü mFragmentsNotifyDataSetChanged () çağrılırken öğelerin konumu .

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

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

Nasıl çalışacağını onaylamak için bu projeyi çalıştırabilirsiniz. https://github.com/cuichanghao/infivt

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.