6

पोर्ट्रेट मोड में, मेरे ViewPager में 3 खंड ए, बी, सी हैं लेकिन लैंडस्केप मोड में, इसमें केवल 2 खंड ए और सी हैं इसलिए मैं प्रत्येक मोड के लिए 2 FragmentStatePagerAdapter एस बनाता हूं। समस्या तब होती है जब स्क्रीन अभिविन्यास बदल जाता है, ViewPager पुराने अभिविन्यास के पिछले खंडों को पुनर्स्थापित करता है और उपयोग करता है। उदाहरण के लिए, जब पोर्ट्रेट से लैंडस्केप में अभिविन्यास बदलते हैं, तो ViewPager अब ए और सी के बजाय 2 खंड ए, बी दिखाता है। मुझे पता है कि ऐसा क्यों होता है लेकिन इसके लिए कोई अच्छा समाधान नहीं मिल रहा है।पोर्ट्रेट और लैंडस्केप के लिए विभिन्न एडाप्टर के साथ ViewPager

मेरा वर्तमान कामकाज ViewPager के लिए अलग-अलग आईडी का उपयोग करना है (उदाहरण के लिए: चित्रों के लिए id/viewpager_portrait और लैंडस्केप लेआउट के लिए id/viewpager_landscape) लेकिन इससे मुझे स्मृति रिसाव का कारण बनता है क्योंकि पुराने टुकड़े को नष्ट नहीं किया जाएगा और अभी भी स्मृति में रखा जाना चाहिए।

मैं गतिविधि के onCreate में कॉल super.onCreate (शून्य) जैसे कुछ वैकल्पिक हल की कोशिश की है, या गतिविधि के onSaveInstanceState में ViewPager के टुकड़े को दूर लेकिन वे सभी मेरे ऐप दुर्घटना बनाता है।

तो मेरा सवाल यह है कि FragmentStatePagerAdapter में अभिविन्यास बदलते समय एक या कई टुकड़ों का पुन: उपयोग करने से कैसे बचें?

किसी भी मदद की सराहना की जाएगी। अग्रिम धन्यवाद।

+0

क्या आपने 'SaveInstanceState' को ओवरराइड करने का प्रयास किया था और उस विधि में 'super.onSaveInstanceState' को कॉल करने से बचें। यह 'फ्रैगमेंट' को सहेजने से रोक देगा। –

+0

यह मेरा वर्तमान कामकाज है, लेकिन इसके बजाय super.onSaveInstanceState को कॉल करने से बचें, मैं ViewPager द्वारा किए गए सभी राज्य को साफ़ करता हूं। और मुझे यह सबसे अच्छा समाधान नहीं लगता है इसलिए मैं अभी भी पूछता हूं क्योंकि कभी-कभी व्यूपेजर के अंदर से एक दुर्घटना दिखाई देती है। – Wayne

उत्तर

3

मुद्दा शायद यह है कि निर्मित Fragment एंड्रॉयड द्वारा प्रदान की रों लिए PagerAdapter कार्यान्वयन को लगता है कि आइटम स्थिर रहेंगे, और इसलिए बनाए रखने और सभी Fragment रों ViewPager में जोड़े गए करने के लिए सूचकांक आधारित संदर्भ पुन: उपयोग। Activity (और Fragment एस) के बाद भी इन संदर्भों को FragmentManager के माध्यम से बनाए रखा जाता है, कॉन्फ़िगरेशन परिवर्तन या प्रक्रिया को मारने के कारण पुनर्निर्मित किया जाता है।

आप क्या करने की जरूरत है कि में प्रत्येक Fragment के साथ एक कस्टम टैग जुड़े हुए हैं और संग्रहीत करता Fragment रों PagerAdapter का अपना स्वयं का कार्यान्वयन लिखना है एक टैग-आधारित प्रारूप (सूचकांक आधारित के बजाय)। getItem() विधि के साथ इंडेक्स के आधार पर एक टैग प्रदान करने के लिए एक सार विधि जोड़ने के बाद आप मौजूदा में से किसी एक से इसका सामान्य कार्यान्वयन प्राप्त कर सकते हैं। बेशक, आपको अनाथ/अप्रयुक्त Fragment एस को ViewPager (जबकि आदर्श रूप से इसके राज्य में रखते हुए) से पिछली कॉन्फ़िगरेशन में जोड़ा जाना होगा।

यदि आप पूरे समाधान को स्वयं लागू नहीं करना चाहते हैं, तो ArrayPagerAdapterCWAC-Pager लाइब्रेरी में इसका थोड़ा सा प्रयास करने के लिए उचित कार्यान्वयन प्रदान करने के लिए उपयोग किया जा सकता है। प्रारंभिकरण पर, आप इसके प्रदत्त टैग के आधार पर प्रासंगिक Fragment को अलग कर सकते हैं, और इसे उपयुक्त के रूप में एडाप्टर से हटा/जोड़ सकते हैं।

+0

मुझे पता है कि अपना खुद का एडाप्टर लिखने से समस्या हल हो जाएगी, लेकिन मुझे लगता है कि इससे बेहतर और आसान समाधान है इसलिए मैं स्टैक ओवरफ्लो से पूछता हूं। – Wayne

+0

@Wayne: मैंने उत्तर के अंत में कुछ और जानकारी जोड़ दी है, और [सीडब्ल्यूएसी-पेजर] (https://github.com/commonsguy/cwac-pager) लाइब्रेरी का उपयोग करने के लिए एक सुझाव भी जोड़ा है। – corsair992

+0

धन्यवाद corsair992, मेरा समाधान पेजर एडाप्टर स्रोत की प्रतिलिपि बनाना है और आपके उत्तर पर कोड बेस का थोड़ा सा परिवर्तन करना है। मुझे खेद है, मैं पिछले सप्ताहांत ऑनलाइन नहीं था इसलिए मैं आपके लिए/ – Wayne

1

अपने एडाप्टर में getItemPosition() ओवरराइड करें और POSITION_NONE लौटाएं। तो जब ViewPager को पुनर्निर्मित किया जाता है तो यह getItemPosition() पर कॉल करेगा और चूंकि आपने यहां से POSITION_NONE वापस कर दिया है, तो यह getItem() पर कॉल करेगा। आपको getItem() से नए टुकड़े वापस करना चाहिए। रेफरी: http://developer.android.com/reference/android/support/v4/view/PagerAdapter.html#getItemPosition%28java.lang.Object%29

+0

के लिए पूर्ण बक्षीस देना भूल गया था, ओह मैं getItemPosition() प्राप्त करने के बारे में भूल गया था। शायद यह एक अच्छा समाधान होगा। धन्यवाद – Wayne

+1

यह उत्तर सही नहीं है। 'ViewPager' केवल 'पेजर एडाप्टर' पर'डेटाडेट चेंज()' को सूचित करने के लिए कॉल पर आइटम पोजिशन में बदलावों की तलाश करता है, और यह किसी भी आइटम को 'FragmentStatePagerAdapter' से किसी भी आइटम को हटाने के लिए ठीक से काम नहीं करेगा क्योंकि यह आइटम को अपरिवर्तनीय मानता है और यह यह गड़बड़ राज्य संघों को गड़बड़ कर देगा। यह 'FragmentPagerAdapter' के लिए काम नहीं करेगा, क्योंकि यह वही चीज़ मानता है, और केवल मूल' Fragment' का पुन: उपयोग करेगा। – corsair992

1

अपने व्यूअर के लिए दो अलग-अलग आईडी का उपयोग क्यों करें, जब आप अपना अभिविन्यास बदलते समय केवल फ्रैगमेंट बी को हटा सकते हैं?

आप onCreateView() या onResume() इस तरह के अंदर अपने टुकड़े (इस उदाहरण में एक माता पिता टुकड़ा अंदर काम करता है, लेकिन यह भी प्रयोग करने योग्य (onResume में की तरह एक माता पिता गतिविधि के अंदर है)) को पुनः प्राप्त कर सकते हैं:

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

    // ... initialize components, etc. 

    pager.setAdapter(pagerAdapter); 

    List<Fragment> children = getChildFragmentManager().getFragments(); 

    if (children != null) { 
     pagerAdapter.restoreFragments(children, orientation); 
    } 
} 

फिर आपके एडाप्टर के अंदर:

@Override 
public void restoreFragments(List<Fragment> fragments, int orientation) { 
    List<Fragment> fragmentsToAdd = new ArrayList<Fragment>(); 
    Collections.fill(fragmentsToAdd, null); 
    if (Configuration.ORIENTATION_LANDSCAPE == orientation) { 
     for (Fragment f : fragments) { 
      if (!(f instanceof FragmentB)) { 
       fragmentsToAdd.add(f); 
      } 
     } 
    } 
    this.fragmentsInAdapter = Arrays.copyOf(temp.toArray(new Fragment[0]), this.fragments.length); // array of all your fragments in your adapter (always refresh them, when config changes, else you have old references in your array! 
    notifyDataSetChanged(); // notify, to remove FragmentB 
} 

यह काम करना चाहिए।

बीटीडब्ल्यू। यदि आप समर्थन लाइब्रेरी V13 का उपयोग कर रहे हैं, तो आप FragmentManager.getFragments() का उपयोग नहीं कर सकते हैं, इस प्रकार आपको उन्हें आईडी या टैग से प्राप्त करने की आवश्यकता होगी।

1

अपनी गतिविधि में ऑनकॉन्फ़िगरेशन चेंज() ओवरराइड करें (एंड्रॉइड: configChanges = "ओरिएंटेशन" को अपनी गतिविधि में जोड़ें) इस तरह आप मैन्युअल रूप से अभिविन्यास परिवर्तन प्रबंधित करते हैं। अब "सब" आपको करना है ऑडऑरिएंटियन चेंजड में एडाप्टर को बदलने के लिए (वर्तमान स्थिति का ट्रैक भी रखें)। इस तरह आप एक सिंगल लेआउट, एक व्यूपेजर का उपयोग करते हैं, और आपको उस खंड के बारे में चिंता करने की ज़रूरत नहीं है जिसे रीसाइक्लिंग नहीं किया जा रहा है (ठीक है, इसके लिए आपको बहुत काम करना होगा)। शुभकामनाएँ!

संबंधित मुद्दे