FragmentPagerAdapter का उपयोग करते समय मौजूदा टुकड़े कैसे प्राप्त करें


99

मुझे अपने टुकड़ों को एक दूसरे के साथ संचार करने में समस्या हो रही है Activity, जो FragmentPagerAdapterकि एक सहायक वर्ग के रूप में उपयोग कर रहा है, जो टैब के प्रबंधन को लागू करता है और एक ViewPagerसाथ जुड़े हुए सभी विवरणों को जोड़ता है TabHost। मैंने FragmentPagerAdapterइसे एंड्रॉइड सैंपल प्रोजेक्ट Support4Demos द्वारा प्रदान किया गया है ।

मुख्य प्रश्न यह है कि FragmentManagerजब मुझे ईद या टैग नहीं है तो मैं विशेष खंड कैसे प्राप्त कर सकता हूं ? FragmentPagerAdapterटुकड़े और ऑटो आईडी और टैग पैदा कर रहा है।



@ jk2K यह एक सवाल का डुप्लिकेट कैसे हो सकता है जो 1 साल बाद पूछा गया था
डेवी

@ डुप्लीकेट एक लेबल की तरह, समय से संबंधित नहीं, बाद में प्रश्नों के उच्च विचार हैं
jk2K

जवाब में से अधिकांश यहाँ तो में मेरा उत्तर जाँच उत्पादन में काम नहीं करते हैं, stackoverflow.com/a/54280113/2413303
EpicPandaForce

जवाबों:


194

समस्या का सारांश

नोट: इस उत्तर में मैं संदर्भ FragmentPagerAdapterऔर इसके स्रोत कोड पर जा रहा हूं । लेकिन सामान्य समाधान भी लागू होना चाहिए FragmentStatePagerAdapter

यदि आप इसे पढ़ रहे हैं, तो आप शायद पहले से ही जानते हैं कि FragmentPagerAdapter/ आपके FragmentStatePagerAdapterलिए बनाने के Fragmentsलिए है ViewPager, लेकिन गतिविधि मनोरंजन पर (चाहे डिवाइस रोटेशन से या सिस्टम आपके मेमोरी को पुनः प्राप्त करने के लिए ऐप को मार रहा हो) ये Fragmentsफिर से नहीं बनाए जाएंगे, बल्कि उनके बजाय उदाहरणों से पुनः प्राप्तFragmentManager । अब कहो कि उन पर काम करने के Activityलिए आपको इनका संदर्भ प्राप्त करने की आवश्यकता है Fragments। आपके पास इन के लिए idया नहीं है क्योंकि उन्हें आंतरिक रूप से सेट करें । तो समस्या यह है कि उस जानकारी के बिना उनके लिए एक संदर्भ कैसे प्राप्त किया जाए ...tagFragmentsFragmentPagerAdapter

वर्तमान समाधान के साथ समस्या: आंतरिक कोड पर निर्भर

बहुत सारे समाधान मैंने इस पर देखे हैं और इसी तरह के प्रश्न मौजूदा बनाएFragment गए कॉल के संदर्भ को प्राप्त करने FragmentManager.findFragmentByTag()और आंतरिक रूप से बनाए गए टैग की"android:switcher:" + viewId + ":" + id नकल करने पर निर्भर करते हैं :। इसके साथ समस्या यह है कि आप आंतरिक स्रोत कोड पर भरोसा कर रहे हैं, जैसा कि हम सभी जानते हैं कि हमेशा के लिए एक ही रहने की गारंटी नहीं है। Google में एंड्रॉइड इंजीनियर आसानी से tagसंरचना को बदलने का निर्णय ले सकते हैं जो आपके कोड को तोड़ देगा जिससे आप मौजूदा का संदर्भ नहीं पा सकेंगे Fragments

आंतरिक पर भरोसा किए बिना वैकल्पिक समाधान tag

यहाँ इसका एक सरल उदाहरण है कि किस तरह से Fragmentsलौटाए गए संदर्भ को प्राप्त करना है FragmentPagerAdapterजो कि आंतरिक tagsसेट पर निर्भर नहीं करता है Fragments। कुंजी इसके बजायinstantiateItem() संदर्भ को ओवरराइड करना और सहेजना है ।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();
        }
    }
}

या यदि आप tagsकक्षा सदस्य चर / संदर्भों के बजाय साथ काम करना पसंद करते हैं तो आप सेट को उसी तरीके से Fragmentsपकड़ भी सकते हैं : नोट: यह लागू नहीं होता है क्योंकि इसे बनाते समय सेट नहीं किया जाता है ।tagsFragmentPagerAdapterFragmentStatePagerAdaptertagsFragments

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

ध्यान दें कि यह विधि आंतरिक tagसेट की नकल करने पर निर्भर नहीं करती है FragmentPagerAdapterऔर इसके बजाय उन्हें पुनर्प्राप्त करने के लिए उचित एपीआई का उपयोग करती है। इस तरह से भले ही tagआप के भविष्य के संस्करणों में परिवर्तन SupportLibraryअभी भी सुरक्षित हो।


यह मत भूलो कि आपके डिजाइन के आधार पर Activity, Fragmentsआप काम करने की कोशिश कर रहे हैं या अभी तक मौजूद नहीं हो सकते हैं, इसलिए आपको nullअपने संदर्भों का उपयोग करने से पहले चेक करके उस पर ध्यान देना होगा।

इसके अलावा, यदि आप इसके बजाय काम कर रहे हैं FragmentStatePagerAdapter, तो आप अपने लिए कठिन संदर्भ नहीं रखना चाहते हैं Fragmentsक्योंकि आपके पास उनमें से कई हो सकते हैं और कठिन संदर्भ अनावश्यक रूप से उन्हें स्मृति में रखेंगे। इसके बजाय मानक के बजाय चर Fragmentमें संदर्भ को बचाएं WeakReference। ऐशे ही:

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
यह वास्तव में एक अच्छा समाधान है, लेकिन इसकी प्रभावशीलता कम होने लगती है यदि आप नहीं जानते हैं कि कितने टुकड़े पारित किए जाएंगे।
Riot Goes Woof

3
@Zorpix आप किसी हाशपैप में बनाए गए अंशों को संग्रहीत कर सकते हैं: map.put (स्थिति, निर्मित फ़्रेग्मेंट);
टॉम बेवेलेंडर

12
यह चेकमार्क का हकदार है! इसे पूरा करने के लिए बहुत ही चतुर और व्यापक तरीका। आपने मुझे बहुत धन्यवाद देने में मदद की है!
young_souvlaki

2
पहले तो यह समाधान बहुत जटिल लग रहा था, इसलिए मैंने इसे छोड़ दिया। मैं अंत में वापस आ गया, हालांकि, क्योंकि अन्य जवाब संतोषजनक नहीं थे। और यह उतना कठिन नहीं था जितना मैंने सोचा था।
सुरागाच

1
कुछ भी ओवरराइड करने की आवश्यकता नहीं है और आपको वास्तव में ओवरराइडिंग नहीं करना चाहिएinstantiateItem । यह करने के लिए उचित तरीके से करने के लिए है फोन instantiateItem में onCreateविधि की अपनी गतिविधि से घिरा हुआ startUpdateहै और finishUpdate। विवरण के लिए मेरा उत्तर देखें
मुर्गेबाई

82

मुझे निम्नलिखित पोस्ट के आधार पर अपने प्रश्न पर उत्तर मिला है: एक टुकड़े में पुनर्मूल्यांकन के टुकड़े

कुछ चीजें जो मैंने सीखी हैं:

  1. getItem(int position)में FragmentPagerAdapterयह विधि वास्तव में क्या करता है के भ्रामक नाम है। यह नए टुकड़े बनाता है, मौजूदा लोगों को वापस नहीं करता है। इतने अर्थ में, इस पद्धति का नाम बदलकर createItem(int position)एंड्रॉइड एसडीके जैसा होना चाहिए । तो यह विधि हमें टुकड़े प्राप्त करने में मदद नहीं करती है।
  2. फ्रैगमेंटपेयरएडस्केप्स के बाद के समर्थन में स्पष्टीकरण के आधार पर पुराने टुकड़ों के संदर्भ में आपको टुकड़ों के निर्माण को छोड़ देना चाहिए FragmentPagerAdapterऔर इस तरह से आपके पास फ्रेगमेंट या उनके टैग का कोई संदर्भ नहीं है। यदि आपके पास फ़्रेग्मेंट टैग है, तो आप FragmentManagerकॉल करके आसानी से इसका संदर्भ प्राप्त कर सकते हैं findFragmentByTag()। हमें दिए गए पृष्ठ की स्थिति में एक टुकड़े के टैग का पता लगाने का एक तरीका चाहिए।

उपाय

अपनी कक्षा में निम्न टैग विधि जोड़ें, जो खंडित टैग को पुनः प्राप्त करें और findFragmentByTag()विधि को भेजें ।

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

ध्यान दें! यह समान पद्धति है जो FragmentPagerAdapterनए टुकड़े बनाते समय उपयोग करती है। इस लिंक को देखें http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/android/support/v2/app/FragmentPagerAdapter.java#104


Btw, इस Q & A में विषय के बारे में और अधिक है: stackoverflow.com/questions/6976027/…
थॉमस

1
viewId इनपुट पैरामीटर क्या है? कौन सा दृश्य?
निलज़ोर

@ निलज़ोर व्यूआईड व्यूपेजर की आईडी है।
डॉ। जैकी

हो सकता है कि यह अनुमान लगाने के बजाय कि यह टुकड़ा अपने टैग को अपनी गतिविधि में बता सके onAttach()?
बेसिन

4
यह सही तरीका नहीं है। @ टोनी चैन का जवाब सबसे अच्छा और सही तरीका है।
मोर्टेजा रस्तगो 13

16

मैन्युअल रूप से टुकड़ा टैग बनाकर आपको instantiateItemआंतरिक makeFragmentNameविधि के साथ संगतता को ओवरराइड करने और न ही निर्भर करने की आवश्यकता नहीं है ।
instantiateItemएक सार्वजनिक तरीका है जिससे आप कर सकते हैं और वास्तव में इसे अपनी गतिविधि के तरीके से कॉल और तरीकों से घिरा होना चाहिए जैसा कि javadoc में वर्णित है :onCreatestartUpdatefinishUpdatePagerAdapter

पेजर एडेप्टर विधि स्टार्टअप (व्यूग्रुप) के लिए एक कॉल इंगित करता है कि व्यू पेजर की सामग्री बदलने वाली है। एक या एक से अधिक कॉलें तत्काल आईटम (व्यूग्रुप, इंट) और / या नष्ट इटेम (व्यूग्रुप, इंट, ऑब्जेक्ट) का पालन करेंगी, और एक अपडेट के अंत को एक कॉल द्वारा सिग्नल किया जाएगा जिसे फिनिशड्यू (व्यूग्रुप) कहा जाएगा।

आप उपरोक्त के माध्यम से, स्थानीय संस्करणों पर अपने अंशों के उदाहरणों को स्टोर कर सकते हैं यदि आपको ज़रूरत है। उदाहरण देखें:

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पहले मौजूदा खंड अंशों के संदर्भ प्राप्त करने का प्रयास करेगा FragmentManager। केवल अगर वे अभी तक मौजूद नहीं हैं, तो यह getItemआपके एडॉप्टर से विधि का उपयोग करके नए बना देगा और FragmentManagerभविष्य के किसी भी उपयोग के लिए उन्हें "स्टोर" करेगा ।

यह नोट करना महत्वपूर्ण है, कि भले ही आपको अपने अंशों के संदर्भ प्राप्त करने की आवश्यकता न हो, फिर भी आपको इस तरह instantiateItemसे startUpdate/ finishUpdateअपने onCreateतरीके से घिरे अपने सभी टैब के लिए कॉल करना चाहिए :

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

आप ऐसा नहीं करते हैं, तो आप को खतरे में डालकर कर रहे हैं कि आपके टुकड़ा उदाहरणों नहीं की जाएगी, प्रतिबद्ध करने के लिए FragmentManager: जब अपनी गतिविधि अग्रभूमि हो जाता है instantiateItemअपने टुकड़े प्राप्त करने के लिए स्वचालित रूप से बुलाया जाएगा, लेकिन startUpdate/ finishUpdate सकता है नहीं (कार्यान्वयन विवरण के आधार पर) और वे क्या मूल रूप से do शुरू / कमिट है FragmentTransaction
यह हो सकता है बनाया टुकड़ा उदाहरणों के लिए संदर्भ में परिणाम बहुत जल्दी खो दिया जा रहा है और आवश्यकता से अधिक अक्सर निर्मित (उदाहरण के लिए जब आप अपनी स्क्रीन बारी बारी से)। आपके टुकड़े कितने "भारी" हैं, इसके आधार पर, इसके गैर-नगण्य प्रदर्शन परिणाम हो सकते हैं।
इसके अलावा, ऐसे मामलों में स्थानीय संस्करणों पर संग्रहीत अंशों के उदाहरण हो सकते हैंबासी हो जाना: यदि एंड्रॉइड प्लेटफ़ॉर्म उन्हें FragmentManagerकिसी भी कारण से प्राप्त करने की कोशिश करता है , तो यह विफल हो जाएगा और इस प्रकार नए बनाएंगे और उपयोग करेंगे, जबकि आपके संस्करण अभी भी पुराने को संदर्भित करेंगे।


1
यह कुछ मामलों में सबसे अच्छा समाधान हो सकता है। लेकिन क्या होगा अगर फ्रैगमेंट मेन्जर टुकड़े को मार देगा और इसे फिर से पढ़ेगा?
वूलट्रान

1
@woltran FragmentManagerसिर्फ बेतरतीब ढंग से मार नहीं सकता है ( नष्ट यहाँ सही शब्द है) अपने Fragment(सोचें कि क्या होगा अगर यह मारने का फैसला किया है Fragmentकि वर्तमान में प्रदर्शित किया जा रहा है;))। आम तौर पर एक Fragmentका जीवनचक्र उसके लिए बाध्य होता है Activity( विवरण के लिए github.com/xxv/android-lifecycle देखें) -> Fragmentयदि नष्ट किया गया हो तो ही उसे नष्ट किया जा सकता है Activity। ऐसे मामले में एक उपयोगकर्ता Navigates दिया करने के लिए वापस जब Activityइसकी onCreateफिर से बुलाया जाएगा और का एक नया उदाहरण Fragmentबनाया जाएगा।
मुर्गेवई

यह वास्तविक उत्तर है
एमजे स्टूडियो

क्या आपको वास्तव में उपयोगकर्ता के रूप में बनाए जा रहे उन पर भरोसा करने के बजाय टुकड़े बनाने चाहिए, उदाहरण के लिए ViewPager स्क्रॉल?
यार

@ यार, तुम सच में करना चाहिए। डॉक्स अंश मैंने स्पष्ट रूप से प्रदान किया है और "कुछ अतिरिक्त जानकारी" अनुभाग बताता है कि क्यों।
मुर्गेवाला

11

जिस तरह से मैंने किया वह परिभाषित हैशेयर ऑफ़ वीकरेफेरेंस इस प्रकार है:

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

फिर मैंने getItem () विधि को इस तरह लिखा:

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

तब आप एक विधि लिख सकते हैं:

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

यह अच्छी तरह से काम करने लगता है और मुझे लगता है कि यह किसी से कम कम हैकी है

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

चाल, क्योंकि यह इस बात पर निर्भर नहीं करता है कि FragmentPagerAdapter कैसे लागू किया जाता है। बेशक अगर टुकड़ा FragmentPagerAdapter द्वारा जारी किया गया है या यदि यह अभी तक नहीं बनाया गया है, तो getFragment शून्य हो जाएगा।

यदि किसी को इस दृष्टिकोण के साथ कुछ गलत लगता है, तो टिप्पणियाँ स्वागत से अधिक हैं।


int fragmentIdint position
15

7
मैं एक बहुत ही समान दृष्टिकोण का उपयोग कर रहा था। लेकिन यह तब विफल होता है जब पेजर को एक सेवस्टैट बंडल से बनाया जाता है। उदाहरण: गतिविधि पृष्ठभूमि में चली जाती है और onSavedStateInstance () के बाद अग्रभूमि में वापस आ जाती है। उस स्थिति में getItem () विधियों को नहीं बुलाया जाएगा।
अनूप

FragmentManager में पहले से ही up2date हमेशा मौजूद रहने के कारण आपका अपना नक्शा बनाने का क्या कारण है? विवरण के लिए मेरा उत्तर देखें।
मुर्गवाई

इसके अलावा, यह तथ्य कि एक टुकड़ा नष्ट हो गया है, यह गारंटी नहीं देता है कि इसके लिए कोई मजबूत संदर्भ नहीं हैं (हालांकि यह संभावना है, लेकिन गारंटी नहीं है ) जिस स्थिति में आपके नक्शे में अभी भी बासी टुकड़े होंगे।
मर्गवई

1
यह सिस्टम सही तरीके से काम नहीं करेगा, क्योंकि सिस्टम फ्रैगमेंट को फिर से बनाता है।
एपिकपांडफ्रीज

10

मैंने इस पद्धति का निर्माण किया जो मेरे लिए वर्तमान टुकड़े का संदर्भ प्राप्त करने के लिए काम कर रही है।

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

बेहतर प्रदर्शन के लिए विधि के बाहर विधि और क्षेत्र को याद करते हुए अच्छा लगा
मार्कोस वास्कोनसेलोस

2

@ personne3000 द्वारा सुझाए गए समाधान अच्छा है, लेकिन इसकी एक समस्या है: जब गतिविधि पृष्ठभूमि में चली जाती है और सिस्टम द्वारा मार दी जाती है (कुछ मुफ्त मेमोरी प्राप्त करने के लिए) और फिर बहाल fragmentReferencesहो जाती है, क्योंकि खाली getItemनहीं होगी , क्योंकि नहीं होगी बुलाया।

नीचे दिया गया वर्ग ऐसी स्थिति को संभालता है:

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

टुकड़ों को संभालने के साथ मुख्य सड़क ब्लॉक आप getItem () पर भरोसा नहीं कर सकते हैं। एक अभिविन्यास परिवर्तन के बाद, टुकड़ों के संदर्भ शून्य हो जाएंगे और getItem () फिर से नहीं कहा जाता है।

यहाँ एक दृष्टिकोण है जो टैग पाने के लिए FragmentPagerAdapter के कार्यान्वयन पर भरोसा नहीं करता है। ओवरट्रीप्ट इटइम (ओवरराइड) को हटा दें जो गेट इट से बनाया गया टुकड़ा लौटा देगा () या टुकड़े प्रबंधक से पाया जाएगा।

@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 से टुकड़ों को लौटाने पर इस पोस्ट को देखें । आपके टुकड़े के सूचकांक को जानने पर आप पर भरोसा करता है - लेकिन यह getItem () में सेट किया जाएगा (केवल तात्कालिकता पर)


0

मैं टैग के बजाय आईडी का उपयोग करके इस मुद्दे को हल करने में कामयाब रहा। (मैं का उपयोग कर रहा हूँ मैं परिभाषित FragmentStatePagerAdapter जो मेरे कस्टम Fragments का उपयोग करता है जिसमें मैं onAttach विधि को ओवररोड करता हूं, जहां आप आईडी को कहीं सहेजते हैं:

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

और फिर आप गतिविधि के अंदर आसानी से टुकड़े तक पहुंच सकते हैं:

Fragment f = getSupportFragmentManager.findFragmentById(fragId);

0

मुझे नहीं पता कि यह सबसे अच्छा तरीका है लेकिन मेरे लिए कुछ और काम नहीं किया। GetActiveFragment सहित अन्य सभी विकल्प शून्य हो गए या ऐप क्रैश हो गया।

मैंने देखा कि स्क्रीन रोटेशन पर टुकड़ा संलग्न किया जा रहा था इसलिए मैंने इसका उपयोग गतिविधि में वापस टुकड़ा भेजने के लिए किया।

टुकड़े में:

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

फिर गतिविधि में:

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

और अंत में गतिविधि चालू करें ():

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

यह दृष्टिकोण एक नया निर्माण किए बिना गतिविधि के वास्तविक दृश्य टुकड़े को संलग्न करता है।


0

सुनिश्चित नहीं है कि अगर मेरा तरीका ऐसा करने का सही या सबसे अच्छा तरीका था क्योंकि मैं जावा / एंड्रॉइड के साथ एक रिश्तेदार शुरुआत कर रहा हूं, लेकिन यह काम करता है (मुझे यकीन है कि यह ऑब्जेक्ट ओरिएंटेड सिद्धांतों का उल्लंघन करता है लेकिन मेरे उपयोग के मामले में कोई अन्य समाधान काम नहीं करता है)।

मेरे पास एक होस्टिंग गतिविधि थी जो एक FragmentStatePagerAdapter के साथ एक ViewPager का उपयोग कर रही थी। FragmentStatePagerAdapter द्वारा बनाए गए Fragments के संदर्भ प्राप्त करने के लिए मैंने खंड वर्ग में एक कॉलबैक इंटरफ़ेस बनाया:

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

होस्टिंग गतिविधि में मैंने इंटरफ़ेस लागू किया और अंशों पर नज़र रखने के लिए एक लिंक्डहाससेट बनाया:

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 वर्ग के भीतर मैंने सूची को OnAttach में जोड़ा और उन्हें OnDetach में निकाल दिया:

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

होस्टिंग गतिविधि के भीतर अब आप FragmentStatePagerAdapter में मौजूद टुकड़ों के माध्यम से पुनरावृति करने के लिए mFragments का उपयोग करने में सक्षम होंगे।


0

यह वर्ग आंतरिक टैग पर भरोसा किए बिना चाल चलता है। चेतावनी: GetFragment विधि का उपयोग करके टुकड़े को एक्सेस किया जाना चाहिए न कि getItem को।

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

बस इस कोड को आज़माएं,

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

नजीब, जैसे मैंने getItem के नीचे दिए अपने जवाब में बताया () मौजूदा लोगों को लौटाने के बजाय एक नया टुकड़ा पैदा कर रहा है क्योंकि कोई भी नाम पाने और न बनाने की उम्मीद कर सकता है । उसी पोस्ट में मेरा समाधान देखें।
इस्मार स्लोमिक

टुकड़ा टुकड़ा = नया YourCustomFragmentClass (); इसके लिए यहां लिखें।
नजीब अहमद पुथवाला 12

मुझे अभी भी समझ में नहीं आया कि यह कैसे इस तथ्य को बदल देता है कि आप मौजूदा एक को पाने के लिए नए टुकड़े पैदा कर रहे हैं ..
Ismar Slomic

आप अभी भी अपने कस्टम टुकड़े के लिए इनिशियलाइज़ करते हैं और वापस लौटते हैं, जैसे Fragment fragment = new YourFragment (); टुकड़ा लौटना;
नजीब अहमद पुथवाला २
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.