FragmentPagerAdapter kullanılırken mevcut parçalar nasıl elde edilir


99

Parçalarımı , sekmelerin yönetimini ve a ile ilişkili tüm ayrıntıları uygulayan yardımcı bir sınıf olarak Activitykullanan aracılığıyla birbirleriyle iletişim kurarken sorun yaşıyorum . Ben hayata geçirdik , Android örnek proje tarafından sağlanmaktadır olarak sadece aynı şekilde Support4Demos .FragmentPagerAdapterViewPagerTabHostFragmentPagerAdapter

Asıl soru, FragmentManagerkimliğim veya Etikete sahip olmadığım zaman belirli bir parçayı nasıl alabilirim ? FragmentPagerAdapterparçaları oluşturmak ve Id ve Etiketleri otomatik olarak oluşturmaktır.



@ jk2K bu nasıl olabilir 1 yıl sonra sorulan bir sorunun kopyası olabilir
Davi

Zaman ile ilgili değil bir etiket gibi yinelenen @Dawit, daha sonra soruları daha yüksek görüşlere sahip
jk2K

Buradaki cevapların çoğu üretimde işe yaramıyor, bu yüzden cevabımı stackoverflow.com/a/54280113/2413303
EpicPandaForce

Yanıtlar:


194

Sorunun özeti

Not: Bu cevapta FragmentPagerAdapterkaynak koduna atıfta bulunacağım. Ancak genel çözüm için de geçerli olmalıdır FragmentStatePagerAdapter.

Bunu okuyorsanız, muhtemelen sizin için yaratmanın FragmentPagerAdapter/ FragmentStatePagerAdapteryaratmanın amaçlandığını zaten biliyorsunuzdur , ancak Aktivite rekreasyonunda (ister cihaz rotasyonundan ister Uygulamanızı yeniden hafızaya almak için uygulamanızı öldüren sistemden) bunlar tekrar oluşturulmayacak, bunun yerine örneklerinden . Şimdi, üzerinde çalışmak için bunlara referans almanız gerektiğini söyleyin. Oluşturulanlar için bir veya yok, çünkü onları dahili olarak ayarlayınFragmentsViewPagerFragmentsFragmentManagerActivityFragmentsidtagFragmentsFragmentPagerAdapter . Yani sorun, bu bilgi olmadan onlara nasıl referans alınacağı ...

Mevcut çözümlerle ilgili sorun: dahili koda güvenmek

Bu ve benzeri sorular üzerinde gördüğüm çözümlerin bir sürü mevcut bir başvuru alma güveniyor Fragmentarayarak FragmentManager.findFragmentByTag()ve taklit içten oluşturulan etiketi:"android:switcher:" + viewId + ":" + id . Bununla ilgili sorun, hepimizin bildiği gibi sonsuza kadar aynı kalacağının garantisi olmayan dahili kaynak koduna güvenmenizdir. Google'daki Android mühendisleri, tagkodunuzu bozacak yapıyı değiştirmeye kolayca karar verebilir ve sizi mevcut bir referans bulamazsınız.Fragments .

İçeriye güvenmeden alternatif çözüm tag

İşte bir başvuru nasıl basit bir örnek Fragmentstarafından döndürülen FragmentPagerAdapteriç güvenmek etmediğini tagsüzerinde kümesi Fragments. Anahtar geçersiz kılma etmektir instantiateItem()orada referansları ve kaydetme yerine içinde getItem().

public class SomeActivity extends Activity {
    private FragmentA m1stFragment;
    private FragmentB m2ndFragment;

    // other code in your Activity...

    private class CustomPagerAdapter extends FragmentPagerAdapter {
        // other code in your custom FragmentPagerAdapter...

        public CustomPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            // Do NOT try to save references to the Fragments in getItem(),
            // because getItem() is not always called. If the Fragment
            // was already created then it will be retrieved from the FragmentManger
            // and not here (i.e. getItem() won't be called again).
            switch (position) {
                case 0:
                    return new FragmentA();
                case 1:
                    return new FragmentB();
                default:
                    // This should never happen. Always account for each position above
                    return null;
            }
        }

        // Here we can finally safely save a reference to the created
        // Fragment, no matter where it came from (either getItem() or
        // FragmentManger). Simply save the returned Fragment from
        // super.instantiateItem() into an appropriate reference depending
        // on the ViewPager position.
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
            // save the appropriate reference depending on position
            switch (position) {
                case 0:
                    m1stFragment = (FragmentA) createdFragment;
                    break;
                case 1:
                    m2ndFragment = (FragmentB) createdFragment;
                    break;
            }
            return createdFragment;
        }
    }

    public void someMethod() {
        // do work on the referenced Fragments, but first check if they
        // even exist yet, otherwise you'll get an NPE.

        if (m1stFragment != null) {
            // m1stFragment.doWork();
        }

        if (m2ndFragment != null) {
            // m2ndFragment.doSomeWorkToo();
        }
    }
}

ya sen çalışmak isterseniz tagssınıf üyesi değişkenleri yerine / atıflar Fragmentssize de kapabilirsiniz tagstarafından seti FragmentPagerAdapteraynı şekilde: NOT: Bu uygulanmaz FragmentStatePagerAdapterayarlandıktan olmadığından tagsit'i oluştururken Fragments.

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
    // get the tags set by FragmentPagerAdapter
    switch (position) {
        case 0:
            String firstTag = createdFragment.getTag();
            break;
        case 1:
            String secondTag = createdFragment.getTag();
            break;
    }
    // ... save the tags somewhere so you can reference them later
    return createdFragment;
}

Bu yöntemin dahili tagseti taklit etmeye dayanmadığını FragmentPagerAdapterve bunun yerine bunları almak için uygun API'leri kullandığını unutmayın. Bu şekilde tagilerideki sürümlerdeki değişiklikler bile SupportLibrarygüvende olacaksınız.


Unutma , aramalarınızdan tasarımına bağlı olduğunu Activity, Fragmentssen olabilir çalışma çalışıyorsanız veya sahip böyle yaparak bunun için hesaba, henüz olmayabilir nullreferanslarını kullanmadan önce çekleri.

Ayrıca, bunun yerine çalışıyorsanız FragmentStatePagerAdapter, o zaman kendinize sıkı referanslar tutmak istemezsiniz Fragmentsçünkü bunların çoğuna sahip olabilirsiniz ve sert referanslar gereksiz yere hafızada tutabilir. Bunun yerine Fragmentreferansları WeakReferencestandart olanlar yerine değişkenlere kaydedin . Bunun gibi:

WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
// ...and access them like so
Fragment firstFragment = m1stFragment.get();
if (firstFragment != null) {
    // reference hasn't been cleared yet; do work...
}

3
Bu gerçekten iyi bir çözüm, ancak kaç parçanın aktarılacağını bilmiyorsanız etkinliğini kaybediyor gibi görünüyor.
Riot Goes Woof

3
@Zorpix, oluşturulan parçaları bir HashMap'te saklayabilirsiniz: map.put (position, createdFragment);
Tom Bevelander

12
Bu onay işaretini hak ediyor! Bunu başarmanın çok zekice ve kapsamlı yolu. Bana çok yardımcı oldun teşekkür ederim!
young_souvlaki

2
İlk başta bu çözüm çok karmaşık görünüyordu, bu yüzden onu atladım. Yine de nihayet geri döndüm, çünkü diğer cevaplar tatmin edici değildi. Ve düşündüğüm kadar zor değildi.
Suragch

1
Gerek şey geçersiz kılmak için ve aslında olmamalıdır geçersiz kılma olması instantiateItem. Bunu yapmanın en uygun yolu etmektir diyoruz instantiateItem içinde onCreateetkinlik çevrili yöntemi startUpdateve finishUpdate. Ayrıntılar için cevabımı görün
morgwai

82

Aşağıdaki gönderiye dayanarak sorumun cevabını buldum: fragmentpageradapter içindeki parçaları yeniden kullanma

Öğrendiğim birkaç şey:

  1. getItem(int position)içinde FragmentPagerAdapterbu yöntem aslında ne yaptığının olduğunu ziyade yanıltıcı isim. Mevcut olanları geri getirmeyen yeni parçalar yaratır. Bu anlamda, yöntem createItem(int position)Android SDK'da olduğu gibi yeniden adlandırılmalıdır . Yani bu yöntem parçalar elde etmemize yardımcı olmuyor.
  2. FragmentPagerAdapterholds post desteğindeki açıklamaya dayanarak, eski parçalara atıfta bulunarak, parçaların oluşturulmasını, FragmentPagerAdapteryani Parçalara veya bunların etiketlerine herhangi bir referansınız olmayacak şekilde bırakmalısınız. Yine de parça etiketiniz varsa, onu FragmentManagerarayarak kolayca referans alabilirsiniz findFragmentByTag(). Belirli bir sayfa konumunda bir parçanın etiketini bulmanın bir yolunu bulmalıyız.

Çözüm

Parça etiketini almak ve findFragmentByTag()yönteme göndermek için sınıfınıza aşağıdaki yardımcı yöntemi ekleyin .

private String getFragmentTag(int viewPagerId, int fragmentPosition)
{
     return "android:switcher:" + viewPagerId + ":" + fragmentPosition;
}

NOT! Bu, FragmentPagerAdapteryeni parçalar oluştururken kullanılan aynı yöntemdir . Bu bağlantıya bakın http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/android/support/v2/app/FragmentPagerAdapter.java#104


Btw, bu Soru-Cevap bölümünde konu hakkında daha fazla bilgi var: stackoverflow.com/questions/6976027/…
Thomas

1
viewId giriş parametresi nedir? Hangi manzara?
Nilzor

@Nilzor viewId, ViewPager'ın kimliğidir.
Dr.jacky

Belki etiketi tahmin etmek yerine, parça etiketinin içindeki etkinliğini söyleyebilir onAttach()?
havza

4
Bu doğru yol değil. @Tony Chan'ın cevabı en iyi ve doğru yoldur.
Murtaza Rastgoo

17

manuel olarak parça etiketleri oluşturarak geçersiz kılmanıza instantiateItemveya dahili makeFragmentNameyöntemle uyumluluğu güvenmenize gerek yoktur .
instantiateItemBir olan kamu yöntem yapabilirsiniz böylece aslında gerektiğini de diyoruz onCreateetkinlik yöntemine çağrıları ile çevrili startUpdateve finishUpdateanlatıldığı gibi yöntemlerle PagerAdapter javadoc :

StartUpdate (ViewGroup) PagerAdapter yöntemine yapılan bir çağrı, ViewPager içeriğinin değişmek üzere olduğunu gösterir. İnstantiateItem (ViewGroup, int) ve / veya destroyItem (ViewGroup, int, Object) için bir veya daha fazla çağrı takip edecek ve bir güncellemenin sonu, finishUpdate (ViewGroup) çağrısı ile bildirilecektir.

Daha sonra yukarıdakileri kullanarak, gerekirse yerel değişkenler üzerinde fragmanlarınızın örneklerine referansları depolayabilirsiniz. Örneğe bakın:

public class MyActivity extends AppCompatActivity {

    Fragment0 tab0; Fragment1 tab1;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.myLayout);
        ViewPager viewPager = (ViewPager) findViewById(R.id.myViewPager);
        MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager());
        viewPager.setAdapter(adapter);
        ((TabLayout) findViewById(R.id.tabs)).setupWithViewPager(viewPager);

        adapter.startUpdate(viewPager);
        tab0 = (Fragment0) adapter.instantiateItem(viewPager, 0);
        tab1 = (Fragment1) adapter.instantiateItem(viewPager, 1);
        adapter.finishUpdate(viewPager);
    }

    class MyPagerAdapter extends FragmentPagerAdapter {

        public MyPagerAdapter(FragmentManager manager) {super(manager);}

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

        @Override public Fragment getItem(int position) {
            if (position == 0) return new Fragment0();
            if (position == 1) return new Fragment1();
            return null;  // or throw some exception
        }

        @Override public CharSequence getPageTitle(int position) {
            if (position == 0) return getString(R.string.tab0);
            if (position == 1) return getString(R.string.tab1);
            return null;  // or throw some exception
        }
    }
}

instantiateItemöncelikle mevcut parça örneklerine referanslar almayı deneyecek FragmentManager. Ancak henüz mevcut değillerse, kullanarak yenilerini oluşturacaktır.getItem adaptörünüzdeki yöntemi ve bunları FragmentManagerileride kullanmak üzere "depolayacaktır" .

Parçalarınıza referanslar almanız gerekmese bile, yine de aşağıdaki gibi yönteminizin içinde / içinde bulunan instantiateItemtüm sekmelerinizi çağırmanız gerektiğini unutmamak önemlidir :startUpdatefinishUpdateonCreate

    adapter.startUpdate(viewPager);
    // ignoring return values of the below 2 calls, just side effects matter:
    adapter.instantiateItem(viewPager, 0);
    adapter.instantiateItem(viewPager, 1);
    adapter.finishUpdate(viewPager);

Bunu yapmazsanız, o zaman parça örnekleri asla o riske vardır taahhüt etmek FragmentManageretkinlik ön plan olduğunda: instantiateItemsenin parçalarını elde etmek otomatik olarak çağrılır, ancak startUpdate/ finishUpdate olabilir değil (uygulama ayrıntılarını bağlı olarak) ve temelde ne do başlamak / yapmaktır a FragmentTransaction.
Bu mayıs ve gerekli olandan çok daha sık yeniden (ekranınızı döndürdüğünüzde örneğin) çok çabuk kaybolmasını oluşturulan parça örneklerine referanslar ile sonuçlanır. Parçalarınızın ne kadar "ağır" olduğuna bağlı olarak, göz ardı edilemeyecek performans sonuçları olabilir.
Ayrıca, bu durumda, fragmanların örnekleri lokal değişkenler depolanmış olabilirbayat: eğer android platformu FragmentManagerherhangi bir nedenle onları almaya çalışırsa , başarısız olur ve böylece yenilerini yaratır ve kullanır, değişkenleriniz hala eski olanları referans alır.


1
Bazı durumlarda en iyi çözüm olabilir. Peki FragmentManger parçayı öldürür ve yeniden değerlendirirse ne olur?
woltran

1
@woltran FragmentManagersadece rastgele olamaz öldürmek ( yok etmek doğru kelime burada) sizin Fragment(bir öldürmeye karar ne olacağını düşünmek Fragmenthalen görüntülenmekte olduğunu;)). Genel olarak a'nın yaşam döngüsü Fragmentona bağlıdır Activity( ayrıntılar için github.com/xxv/android-lifecycle'a bakın) -> a Fragmentyalnızca yok edilirse Activityyok edilebilir. Böyle bir durumda, bir kullanıcı dolaşır verilen etmek için geri zaman Activityonun onCreatetekrar adı verilecek ve yeni bir örneği Fragmentoluşturulur.
morgwai

GERÇEK Cevap Bu
MJ Studio

Örneğin, bir kullanıcı ViewPager'ı kaydırırken oluşturulmalarına güvenmek yerine gerçekten parçalar mı oluşturmalısınız?
Yar

@Yar evet, gerçekten yapmalısın. Sağladığım belgelerden alıntı açıkça belirtiyor ve "Bazı ek bilgiler" bölümü nedenini açıklıyor.
morgwai

11

Bunu yaptığım şekilde bir Zayıf Referanslar Hashtable'ını aşağıdaki gibi tanımladım:

protected Hashtable<Integer, WeakReference<Fragment>> fragmentReferences;

Sonra getItem () yöntemini şöyle yazdım:

@Override
public Fragment getItem(int position) {

    Fragment fragment;
    switch(position) {
    case 0:
        fragment = new MyFirstFragmentClass();
        break;

    default:
        fragment = new MyOtherFragmentClass();
        break;
    }

    fragmentReferences.put(position, new WeakReference<Fragment>(fragment));

    return fragment;
}

Sonra bir yöntem yazabilirsiniz:

public Fragment getFragment(int fragmentId) {
    WeakReference<Fragment> ref = fragmentReferences.get(fragmentId);
    return ref == null ? null : ref.get();
}

Bu iyi çalışıyor gibi görünüyor ve bunu,

"android:switcher:" + viewId + ":" + position

FragmentPagerAdapter'ın nasıl uygulandığına bağlı değildir. Elbette, fragment FragmentPagerAdapter tarafından serbest bırakıldıysa veya henüz yaratılmadıysa, getFragment null döndürür.

Herhangi biri bu yaklaşımda yanlış bir şey bulursa, yorumlar memnuniyetle karşılanır.


int fragmentIdolarak yeniden adlandırılmalıdırint position
lmaooooo

7
Ben de çok benzer bir yaklaşım kullanıyordum. Ancak bu, çağrı cihazı bir SavedState paketinden oluşturulduğunda başarısız olur. örneğin: Etkinlik arka plana gider ve onSavedStateInstance () çağrıldıktan sonra ön plana geri döner. Bu durumda getItem () yöntemleri çağrılmayacaktır.
Anoop

FragmentManager'da zaten her zaman up2date olan bir harita olduğu için kendi haritanızı oluşturmanın nedeni nedir? Ayrıntılar için cevabıma bakın.
morgwai

Ayrıca, bir parçası tahrip edilmiş olması, (büyük olasılıkla, ama her ne kadar kendisine hiçbir güçlü referansları vardır garanti etmez DEĞİL garantili) bu durumda haritanızın bayat parçalarını hala içerecektir.
morgwai

1
Sistem Parçaları yeniden oluşturduktan sonra bu doğru çalışmayacaktır.
EpicPandaForce

10

Mevcut parçaya referans almam için çalışan bu yöntemi yarattım.

public static Fragment getCurrentFragment(ViewPager pager, FragmentPagerAdapter adapter) {
    try {
        Method m = adapter.getClass().getSuperclass().getDeclaredMethod("makeFragmentName", int.class, long.class);
        Field f = adapter.getClass().getSuperclass().getDeclaredField("mFragmentManager");
        f.setAccessible(true);
        FragmentManager fm = (FragmentManager) f.get(adapter);
        m.setAccessible(true);
        String tag = null;
        tag = (String) m.invoke(null, pager.getId(), (long) pager.getCurrentItem());
        return fm.findFragmentByTag(tag);
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } 
    return null;
}

Daha iyi performans için Metot ve
Alan'ı

2

@ personne3000 tarafından önerilen çözüm güzel, ancak bir sorunu var: etkinlik arka plana gidip sistem tarafından öldürüldüğünde (biraz boş bellek elde etmek için) ve sonra geri yüklendiğinde, fragmentReferencesboş olacaktır, çünkügetItem olmayacak aranan.

Aşağıdaki sınıf böyle bir durumu ele alır:

public abstract class AbstractHolderFragmentPagerAdapter<F extends Fragment> extends FragmentPagerAdapter {

    public static final String FRAGMENT_SAVE_PREFIX = "holder";
    private final FragmentManager fragmentManager; // we need to store fragment manager ourselves, because parent's field is private and has no getters.

    public AbstractHolderFragmentPagerAdapter(FragmentManager fm) {
        super(fm);
        fragmentManager = fm;
    }

    private SparseArray<WeakReference<F>> holder = new SparseArray<WeakReference<F>>();

    protected void holdFragment(F fragment) {
        holdFragment(holder.size(), fragment);
    }

    protected void holdFragment(int position, F fragment) {
        if (fragment != null)
            holder.put(position, new WeakReference<F>(fragment));
    }

    public F getHoldedItem(int position) {
        WeakReference<F> ref = holder.get(position);
        return ref == null ? null : ref.get();
    }

    public int getHolderCount() {
        return holder.size();
    }

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) { // code inspired by Google's FragmentStatePagerAdapter implementation
        super.restoreState(state, loader);
        Bundle bundle = (Bundle) state;
        for (String key : bundle.keySet()) {
            if (key.startsWith(FRAGMENT_SAVE_PREFIX)) {
                int index = Integer.parseInt(key.substring(FRAGMENT_SAVE_PREFIX.length()));
                Fragment f = fragmentManager.getFragment(bundle, key);
                holdFragment(index, (F) f);
            }
        }
    }

    @Override
    public Parcelable saveState() {
        Bundle state = (Bundle) super.saveState();
        if (state == null)
            state = new Bundle();

        for (int i = 0; i < holder.size(); i++) {
            int id = holder.keyAt(i);
            final F f = getHoldedItem(i);
            String key = FRAGMENT_SAVE_PREFIX + id;
            fragmentManager.putFragment(state, key, f);
        }
        return state;
    }
}

1

Parçalara bir tutamaç elde etmenin ana yol bloğu, getItem () 'e güvenememenizdir. Bir yönelim değişikliğinden sonra, parçalara yapılan başvurular boş olacaktır ve getItem () tekrar çağrılmaz.

Etiketi almak için FragmentPagerAdapter uygulamasına dayanmayan bir yaklaşım aşağıda verilmiştir. GetItem () 'den oluşturulan veya parça yöneticisinden bulunan parçayı döndürecek olan instantiateItem () öğesini geçersiz kılın.

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object value =  super.instantiateItem(container, position);

    if (position == 0) {
        someFragment = (SomeFragment) value;
    } else if (position == 1) {
        anotherFragment = (AnotherFragment) value;
    }

    return value;
}

0

FragmentPagerAdapter'dan parçaları döndürme hakkındaki bu gönderiye bakın. Parçanızın dizinini bilmenize güveniyor - ancak bu getItem () içinde ayarlanacaktır (yalnızca somutlaştırmada)


0

Bu sorunu etiketler yerine kimlikler kullanarak çözmeyi başardım. (Kimliği bir yere kaydettiğiniz onAttach yöntemini geçersiz kıldığım özel Fragments'ımı kullanan FragmentStatePagerAdapter'ı kullanıyorum:

@Override
public void onAttach(Context context){
    super.onAttach(context);
    MainActivity.fragId = getId();
}

Ve sonra, aktivitenin içindeki parçaya kolayca erişirsiniz:

Fragment f = getSupportFragmentManager.findFragmentById(fragId);

0

Bunun en iyi yaklaşım olup olmadığını bilmiyorum ama benim için başka hiçbir şey işe yaramadı. GetActiveFragment dahil diğer tüm seçenekler boş döndürdü veya uygulamanın çökmesine neden oldu.

Ekran döndürüldüğünde parçanın eklendiğini fark ettim, bu yüzden parçayı aktiviteye geri göndermek için kullandım.

Parçada:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
        mListener = (OnListInteractionListener) activity;
        mListener.setListFrag(this);
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement OnFragmentInteractionListener");
    }
}

Daha sonra aktivitede:

@Override
public void setListFrag(MyListFragment lf) {
    if (mListFragment == null) {
        mListFragment = lf;
    }
}

Ve son olarak onCreate () etkinliğinde:

if (savedInstanceState != null) {
    if (mListFragment != null)
        mListFragment.setListItems(items);
}

Bu yaklaşım, gerçek görünür parçayı yeni bir tane oluşturmadan etkinliğe ekler.


0

Java / Android ile göreceli olarak yeni başladığım için yöntemimin bunu yapmanın doğru veya en iyi yolu olup olmadığından emin değilim, ancak işe yaradı (nesneye yönelik ilkeleri ihlal ettiğinden eminim, ancak kullanım durumum için başka hiçbir çözüm işe yaramadı).

FragmentStatePagerAdapter ile ViewPager kullanan bir barındırma Etkinliğim vardı. FragmentStatePagerAdapter tarafından oluşturulan Fragmentlere referanslar almak için fragment sınıfı içinde bir geri çağırma arayüzü oluşturdum:

public interface Callbacks {
    public void addFragment (Fragment fragment);
    public void removeFragment (Fragment fragment);
}

Barındırma etkinliğinde arayüzü uyguladım ve parçaların kaydını tutmak için bir LinkedHasSet oluşturdum:

public class HostingActivity extends AppCompatActivity implements ViewPagerFragment.Callbacks {

    private LinkedHashSet<Fragment> mFragments = new LinkedHashSet<>();

    @Override
    public void addFragment (Fragment fragment) {
        mFragments.add(fragment);
    }

    @Override
    public void removeFragment (Fragment fragment) {
        mFragments.remove(fragment);
    }
}

ViewPagerFragment sınıfı içinde parçaları onAttach içindeki listeye ekledim ve onDetach içinde kaldırdım:

public class ViewPagerFragment extends Fragment {

    private Callbacks mCallbacks;

    public interface Callbacks {
        public void addFragment (Fragment fragment);
        public void removeFragment (Fragment fragment);
    } 

    @Override
    public void onAttach (Context context) {
        super.onAttach(context);
        mCallbacks = (Callbacks) context;
        // Add this fragment to the HashSet in the hosting activity
        mCallbacks.addFragment(this);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        // Remove this fragment from the HashSet in the hosting activity
        mCallbacks.removeFragment(this);
        mCallbacks = null;
    }
}

Barındırma etkinliği içinde, şu anda FragmentStatePagerAdapter içinde bulunan parçaları yinelemek için mFragments'ı artık kullanabileceksiniz.


0

Bu sınıf, dahili etiketlere güvenmeden hile yapar. Uyarı: Parçalara getItem one değil getFragment yöntemi kullanılarak erişilmelidir.

public class ViewPagerAdapter extends FragmentPagerAdapter {

    private final Map<Integer, Reference<Fragment>> fragments = new HashMap<>();
    private final List<Callable0<Fragment>> initializers = new ArrayList<>();
    private final List<String> titles = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    void addFragment(Callable0<Fragment> initializer, String title) {
        initializers.add(initializer);
        titles.add(title);
    }

    public Optional<Fragment> getFragment(int position) {
        return Optional.ofNullable(fragments.get(position).get());
    }

    @Override
    public Fragment getItem(int position) {
        Fragment fragment =  initializers.get(position).execute();
        return fragment;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        fragments.put(position, new WeakReference<>(fragment));
        return fragment;
    }

    @Override
    public int getCount() {
        return initializers.size();
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return titles.get(position);
    }
}

-5

Devam edin bu kodu deneyin,

public class MYFragmentPAdp extends FragmentPagerAdapter {

    public MYFragmentPAdp(FragmentManager fm) {
        super(fm);
    }

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

     @Override
     public Fragment getItem(int position) {
         if (position == 0)
             Fragment fragment = new Fragment1();
         else (position == 1)
             Fragment fragment = new Fragment2();
         return fragment;
     }
}

Najib, aşağıdaki cevabımda açıkladığım gibi getItem (), verilen adın olsun ve olmasın beklendiği gibi mevcut olanları geri döndürmek yerine yeni bir parça yaratıyor . Çözümüme aynı gönderide bakın.
Ismar Slomic

Fragment fragment = new YourCustomFragmentClass (); buraya yazın bunu kontrol edin.
Najib Ahmed Puthawala

Halen mevcut olanı elde etmek yerine yeni bir fragman yarattığınız gerçeğini nasıl değiştirdiğini anlamıyorum ..
Ismar Slomic

Yine de, Fragment fragment = new YourFragment () gibi, yalnızca özel parçanız için başlatıp geri dönersiniz; dönüş parçası;
Najib Ahmed Puthawala
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.