ViewPager को गतिशील रूप से अपडेट करें?


316

मैं ViewPager में सामग्री को अपडेट नहीं कर सकता।

FragmentPagerAdapter वर्ग में तत्काल तरीके () और getItem () के तरीकों का सही उपयोग क्या है?

मैं केवल getItem () का उपयोग अपने अंशों को त्वरित और वापस करने के लिए कर रहा था:

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

इसने अच्छा काम किया। सिवाय मैं सामग्री को बदल नहीं सकता।

इसलिए मुझे यह मिला: ViewPager PagerAdapter दृश्य को अपडेट नहीं कर रहा है

"मेरा दृष्टिकोण तात्कालिकता () विधि में किसी भी तात्कालिक दृश्य के लिए सेटटैग () विधि का उपयोग करना है"

अब मैं InstantiateItem () को लागू करना चाहता हूं। लेकिन मुझे नहीं पता कि मुझे क्या लौटना है (प्रकार वस्तु है) और गेटआईएम (अंतर स्थिति) के साथ क्या संबंध है?

मैंने संदर्भ पढ़ा :

  • सार्वजनिक सार फ्रेगमेंट getItem (int स्थिति)

    एक निर्दिष्ट स्थिति से जुड़े फ्रैगमेंट लौटें।

  • सार्वजनिक वस्तु InstantiateItem (ViewGroup कंटेनर, int स्थिति)

    दिए गए पद के लिए पृष्ठ बनाएँ। एडेप्टर यहाँ दिए गए कंटेनर में दृश्य जोड़ने के लिए ज़िम्मेदार है, हालांकि यह केवल यह सुनिश्चित करना चाहिए कि यह उस समय तक किया जाता है जब यह फिनिश यूडेटड (व्यूग्रुप) से लौटता है। पैरामीटर

    कंटेनर जिसमें व्यू दिखाई देगा जिसमें पेज दिखाया जाएगा। स्थिति पृष्ठ स्थिति को तत्काल किया जा सकता है।

    रिटर्न

    नए पृष्ठ का प्रतिनिधित्व करने वाली वस्तु देता है। इसके लिए व्यू होने की आवश्यकता नहीं है, लेकिन पेज के कुछ अन्य कंटेनर हो सकते हैं।

लेकिन मुझे अभी भी नहीं मिला।

यहाँ मेरा कोड है। मैं समर्थन पैकेज v4 का उपयोग कर रहा हूं।

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

यहाँ भी एक ऐसी ही समस्या है, जिसका कोई उत्तर नहीं है


इसमें शामिल घटकों की बेहतर समझ प्राप्त करने के लिए, यह अलग टैब नेविगेशन इतिहास के साथ एक tabbed ViewPager के बारे में मेरे ट्यूटोरियल को पढ़ने में मदद कर सकता है। : यह GitHub और अतिरिक्त संसाधनों पर एक काम उदाहरण के साथ आता है medium.com/@nilan/...
marktani

कुछ समस्या मिली stackoverflow.com/questions/40149039/…
अल्बर्ट

आप इस उदाहरण को GitHub में देख सकते हैं । मुझे उम्मीद है कि यह उदाहरण आपकी मदद करता है।
काबिजस

अच्छा सरल समाधान: stackoverflow.com/a/35450575/2162226
जीन बो

Google ने हाल ही में ViewPager2 की शुरुआत की, जो डायनेमिक फ़्रैगमेंट / व्यू अपडेट को सरल बनाता है। आप github.com/googlesamples/android-viewpager2 पर छूट देख सकते हैं या इस जवाब पर stackoverflow.com/a/57393414/1333448
यव्स डेलर्म

जवाबों:


605

FragmentPagerAdapter या FragmentStatePagerAdapter का उपयोग करते समय, यह पूरी तरह से निपटने getItem()और instantiateItem()सभी को छूने के लिए नहीं है । instantiateItem()- destroyItem()- isViewFromObject()PagerAdapter पर इंटरफ़ेस एक कम-स्तर इंटरफ़ेस है कि FragmentPagerAdapter का उपयोग करता है बहुत सरल लागू करने के लिए है getItem()इंटरफ़ेस।

इस पर विचार करने से पहले, मुझे यह स्पष्ट करना चाहिए

यदि आप प्रदर्शित किए जाने वाले वास्तविक अंशों को बंद करना चाहते हैं, तो आपको FragmentPagerAdapter से बचने और FragmentStatePagerAdapter का उपयोग करने की आवश्यकता है।

इस उत्तर के एक पुराने संस्करण ने अपने उदाहरण के लिए FragmentPagerAdapter का उपयोग करने की गलती की - यह काम नहीं करेगा क्योंकि FragmentPagerAdapter पहली बार प्रदर्शित होने के बाद कभी भी एक टुकड़े को नष्ट नहीं करता है।

मैं आपके द्वारा लिंक किए गए पोस्ट में प्रदान किए गए setTag()और findViewWithTag()वर्कअराउंड की अनुशंसा नहीं करता । जैसा कि आपने खोज किया है, टुकड़ों का उपयोग करना setTag()और findViewWithTag()काम नहीं करता है, इसलिए यह एक अच्छा मैच नहीं है।

सही समाधान ओवरराइड करना है getItemPosition()। जब notifyDataSetChanged()कहा जाता है, तो ViewPager getItemPosition()अपने एडॉप्टर में सभी वस्तुओं को कॉल करता है यह देखने के लिए कि क्या उन्हें एक अलग स्थिति में ले जाने या हटाने की आवश्यकता है।

डिफ़ॉल्ट रूप से, getItemPosition()रिटर्न POSITION_UNCHANGED, जिसका अर्थ है, "यह ऑब्जेक्ट ठीक है जहां यह है, इसे नष्ट या हटाएं नहीं।" लौटकर POSITION_NONEसमस्या को यह कहते हुए ठीक करता है कि, "यह वस्तु अब प्रदर्शित होने वाली वस्तु नहीं है, इसे हटा दें।" तो यह आपके एडॉप्टर में हर एक आइटम को हटाने और फिर से बनाने का प्रभाव है।

यह पूरी तरह से वैध फिक्स है! यह फ़िक्स नोटिफ़िकेशनडायसेटचेंज किए हुए को रेगुलर एडेप्टर की तरह व्यवहार करता है। यदि आप इस सुधार को लागू करते हैं और प्रदर्शन संतोषजनक है, तो आप दौड़ से बाहर हो जाएंगे। काम हो गया।

यदि आपको बेहतर प्रदर्शन की आवश्यकता है, तो आप एक कट्टर getItemPosition()कार्यान्वयन का उपयोग कर सकते हैं । यहाँ स्ट्रिंग की सूची से अलग टुकड़े बनाने वाले पेजर के लिए एक उदाहरण है:

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

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

क्या होगा अगर टुकड़ा को फिर से बनाया नहीं गया है, लेकिन वैसे भी अपडेट किए जाने की आवश्यकता है? एक जीवित टुकड़े के अपडेट को सबसे अच्छा खंड द्वारा ही नियंत्रित किया जाता है। यह एक टुकड़ा होने का लाभ है, आखिरकार - यह अपना नियंत्रक है। एक टुकड़ा एक श्रोता या एक पर्यवेक्षक को किसी अन्य ऑब्जेक्ट में जोड़ सकता है onCreate(), और फिर इसे हटा सकता है onDestroy(), इस प्रकार अपडेट को स्वयं प्रबंधित कर सकता है। आपको सभी अपडेट कोड अंदर नहीं डालने होंगेgetItem() , जैसे आप एक सूची दृश्य या अन्य एडेप्टर व्यू प्रकार के लिए एक एडॉप्टर में करते हैं।

एक आखिरी बात - सिर्फ इसलिए कि FragmentPagerAdapter के एक टुकड़े को नष्ट नहीं करता है इसका मतलब यह नहीं है कि GetItemPosition एक FragmentPagerAdapter में पूरी तरह से बेकार है। ViewPager में अपने अंशों को पुन: व्यवस्थित करने के लिए आप इस कॉलबैक का उपयोग कर सकते हैं। यह उन्हें पूरी तरह से FragmentManager से कभी नहीं हटाएगा, हालाँकि।


4
काम नहीं करता है, यह अभी भी कुछ भी अपडेट नहीं कर रहा है ... मेरे कोड को पोस्ट किया।
Ixx

64
ठीक है, इस समस्या का पता लगा लिया - आपको FragmentStatePagerAdapter के बजाय FragmentPagerAdapter का उपयोग करने की आवश्यकता है। FragmentPagerAdapter कभी भी FragmentManager के टुकड़े नहीं हटाता है, यह केवल उन्हें अलग करता है और उन्हें संलग्न करता है। अधिक जानकारी के लिए डॉक्स की जांच करें - सामान्य तौर पर, आप केवल उन टुकड़ों के लिए FragmentPagerAdapter का उपयोग करना चाहते हैं जो स्थायी हैं। मैंने अपना उदाहरण सुधार के साथ संपादित किया है।
बिल फिलिप्स

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

12
आप सही हैं, एडेप्टर के वर्ग को बदलकर FragmentStatePagerAdapter ने मेरी सारी परेशानी को ठीक कर दिया। धन्यवाद!
Ixx

2
यहां तक ​​कि जब मैं POSITION_NONE वापस करता हूं, तो उपयोग करते समय FragmentStatePagerAdapter, मैं देख सकता हूं कि यह मेरे टुकड़े को हटा देता है और नया उदाहरण बनाता है। लेकिन नया उदाहरण एक पुराने टुकड़े की स्थिति के साथ एक SaveInstanceState बंडल प्राप्त करता है। मैं फिर से बनाए जाने पर बंडल को पूरी तरह से कैसे नष्ट कर सकता हूं?
singed

142

लौटने के बजाय POSITION_NONEसे getItemPosition()और पूर्ण दृश्य मनोरंजन के कारण, ऐसा करते हैं:

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

आपके टुकड़ों को UpdateableFragmentइंटरफ़ेस लागू करना चाहिए :

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

और इंटरफ़ेस:

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

आपका डेटा वर्ग:

public class UpdateData {
    //whatever you want here
}

1
क्या इसका मतलब यह है कि आपके MainActivity को भी इंटरफ़ेस लागू करने की आवश्यकता है ??? कृपया इसमें मेरी सहायता करें। मेरे वर्तमान कार्यान्वयन में, मैं टुकड़ों के बीच एक संचारक के रूप में अपने MainActivity वर्ग का उपयोग कर रहा हूं, इसलिए मैं इस समाधान के बारे में उलझन में था।
राकेब राजभँदरी

1
ठीक है, मैंने पूरे कार्यान्वयन के साथ एक और जगह पर उत्तर दिया है जहां मैं Fragmentगतिशील रूप से अपडेट कर रहा हूं , एक नज़र डालें: stackoverflow.com/questions/19891828/…
M-WaJeEh

@ M-WaJeEh शायद कुछ उदाहरण कृपया !!! मेरे पास शहरों की सूची के साथ एक सूची है और शहर का चयन करने के बाद इस शहर के बारे में जानकारी के साथ दृश्य पृष्ठ (3 पृष्ठ) खोलता है। यह ठीक काम करता है। लेकिन दूसरे शहर के व्यूपेजर के चयन के बाद केवल 3 d page on refreshes the 1-st page only after swiping pages? thw 2डी पेज हमेशा खाली होता है। धन्यवाद
SERG

4
अपने काम के जीवन के पिछले 2.5 दिनों के लिए देखे गए सभी सामानों के बीच .. यह एकमात्र ऐसा काम है जो मेरे लिए काम करता है .. सभी प्रकार के अरिगैटो, धन्यवाद, स्पैसिबा, सुक्रान .. एन।
ऑर्कुन ओजेन

2
ड्रेगन की माँ!, यह एक आकर्षण की तरह काम करता है, एकमात्र समाधान मेरे लिए काम करता है ... बहुत कुछ !!
सेबेस्टियन गुरेरो

24

उन लोगों के लिए जो अभी भी उसी समस्या का सामना कर रहे हैं, जिसका सामना मैंने पहले किया था जब मेरे पास ViewPager7 टुकड़े थे। इन अंशों के लिए डिफ़ॉल्ट, अंग्रेजी सामग्री को APIसेवा से लोड करने के लिए, लेकिन यहां समस्या यह है कि मैं सेटिंग्स गतिविधि से भाषा को बदलना चाहता हूं और सेटिंग गतिविधियों को समाप्त करने के बाद मैं ViewPagerमुख्य गतिविधि में उपयोगकर्ता से भाषा के चयन से मेल खाने के लिए टुकड़ों को ताज़ा करना चाहता हूं और लोड करना चाहता हूं अरबी सामग्री अगर उपयोगकर्ता अरबी का चयन यहां करता है जो मैंने पहली बार काम करने के लिए किया था

1- ऊपर बताए अनुसार आपको FragmentStatePagerAdapter का उपयोग करना चाहिए।

2- मेनऐक्टिविटी पर मैंने ओनड्यूम को ओवरराइड किया और निम्नलिखित कार्य किया

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

3-i getItemPosition()ने mPagerAdapter में ओवरराइड किया और इसे वापस कर दिया POSITION_NONE

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

आकर्षण की तरह काम करता है


1
एक सिचुएशन को छोड़कर काम करता है। जब आप viewPager में अंतिम आइटम हटाते हैं। तब यह सूची से नहीं हटता है।
व्लादो पांडेसिएक

मैं दृश्य टुकड़ा में गतिशील रूप से वर्तमान टुकड़े के बाईं और दाईं ओर टुकड़े जोड़ रहा था। यह एक काम किया! धन्यवाद।
h8pathak

15

मैंने इस समस्या का सामना किया है और आखिरकार आज इसे हल कर दिया है, इसलिए मैं यह लिखता हूं कि मैंने क्या सीखा है और मुझे आशा है कि यह किसी के लिए उपयोगी है जो एंड्रॉइड के लिए नया है ViewPagerऔर जैसा मैं करता हूं उसे अपडेट करें। मैं FragmentStatePagerAdapterएपीआई स्तर 17 में उपयोग कर रहा हूं और वर्तमान में सिर्फ 2 टुकड़े हैं। मुझे लगता है कि कुछ सही नहीं होना चाहिए, कृपया मुझे सही करें, धन्यवाद। यहां छवि विवरण दर्ज करें

  1. सीरियल डेटा को मेमोरी में लोड किया जाना है। यह CursorLoader/ AsyncTask/ का उपयोग करके किया जा सकता है Thread। क्या यह स्वचालित रूप से लोड है आपके कोड पर निर्भर करता है। यदि आप एक का उपयोग कर रहे हैं CursorLoader, यह एक पंजीकृत डेटा पर्यवेक्षक के बाद से स्वतः लोड है।

  2. आपके द्वारा कॉल करने के बाद viewpager.setAdapter(pageradapter), एडैप्टर getCount()को लगातार टुकड़े बनाने के लिए बुलाया जाता है। इसलिए यदि डेटा लोड किया जा रहा है, तो getCount()0 वापस कर सकते हैं, इस प्रकार आपको दिखाए गए डेटा के लिए डमी टुकड़े बनाने की आवश्यकता नहीं है।

  3. डेटा लोड होने के बाद, एडेप्टर getCount()0 के बाद से स्वचालित रूप से टुकड़ों का निर्माण नहीं करेगा , इसलिए हम वास्तव में लोड किए गए डेटा नंबर को वापस करने के लिए सेट कर सकते हैं getCount(), फिर एडेप्टर को कॉल करें notifyDataSetChanged()ViewPagerस्मृति में डेटा द्वारा टुकड़े (सिर्फ पहले 2 टुकड़े) बनाना शुरू करें। यह notifyDataSetChanged()लौटाए जाने से पहले किया गया है। तो फिर ViewPagerसही टुकड़े आप की जरूरत है

  4. यदि डेटाबेस में डेटा और मेमोरी दोनों अपडेटेड हैं (लिखकर लिखें), या मेमोरी में सिर्फ डेटा अपडेटेड है (राइट बैक करें), या डेटाबेस में केवल डेटा ही अपडेट होता है। पिछले दो मामलों में यदि डेटा को डेटाबेस से मेमोरी में लोड नहीं किया गया है (जैसा कि ऊपर उल्लेख किया गया है)। ViewPagerऔर पेजर एडाप्टर सिर्फ स्मृति में डेटा के साथ सौदा।

  5. इसलिए जब मेमोरी में डेटा अपडेट होता है, तो हमें बस एडॉप्टर को कॉल करना होगा notifyDataSetChanged()। चूंकि टुकड़ा पहले से ही बना है, इसलिए रिटर्न onItemPosition()से पहले एडॉप्टर को बुलाया जाएगा notifyDataSetChanged()। कुछ भी करने की जरूरत नहीं है getItemPosition()। फिर डेटा को अपडेट किया जाता है।


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

क्या किसी को इस बात का अंदाजा है कि उस आरेख को बनाने के लिए किस उपकरण का उपयोग किया गया था?
जुइसी

12

अपने कोड के destroyDrawingCache()बाद ViewPager पर प्रयास करें notifyDataSetChanged()


3
मुझे भी। बहुत धन्यवाद काम करता है। मेरे पास विशेष रूप से एक कठिन समय था क्योंकि मैं Fragmentsअपने दृश्य पेजर में उपयोग नहीं कर रहा हूं । इसलिए धन्यवाद!
सेठ

11

हताशा के घंटे इस समस्या को दूर करने के लिए सब से ऊपर समाधान की कोशिश कर रहा है और यह भी जैसे अन्य इसी तरह के सवाल पर कई समाधान की कोशिश कर थोड़ी देर के बाद यह , यह और यह जो सभी मेरे साथ विफल इस समस्या को हल करने के लिए और बनाने के लिए ViewPagerपुराने को नष्ट करने Fragmentऔर भरने के pagerसाथ नया Fragmentएस। मैंने निम्नलिखित समस्या का समाधान किया है:

1) निम्नानुसार ViewPagerविस्तार करने के लिए कक्षा बनाएं FragmentPagerAdapter:

 public class myPagerAdapter extends FragmentPagerAdapter {

2)ViewPager उस स्टोर के लिए एक आइटम बनाएं titleऔर fragmentनिम्न के रूप में:

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) इसे मेरे रूप में स्टोर करने के ViewPagerलिए मेरे FragmentManagerउदाहरण का निर्माण करें class:

private FragmentManager mFragmentManager;
private ArrayList<PagerItem> mPagerItems;

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

4)adapter नए डेटा के साथ डेटा को फिर से सेट करने के लिए एक विधि बनाएं, जो पहले fragmentसे fragmentManagerही सीधे नए सूची से नए adapterसेट करने के लिए fragmentनिम्न के रूप में खुद को सीधे हटाकर :

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) कंटेनर से Activityया Fragmentनए डेटा के साथ एडेप्टर को फिर से शुरू न करें। विधि के माध्यम setPagerItemsसे नए डेटा को नए डेटा के साथ निम्नानुसार सेट करें:

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

मुझे उम्मीद है यह मदद करेगा।


क्या आप मुझे मेरे मुद्दे में मदद कर सकते हैं stackoverflow.com/questions/40149039/…
अल्बर्ट

क्या आप मुझे इस समस्या से
viper

10

किसी कारण से किसी भी उत्तर ने मेरे लिए काम नहीं किया, इसलिए मुझे अपने फ्रेग्मेंटस्टेट पेजएगर एडॉप्टर में सुपर को कॉल किए बिना रिस्टोरस्ट विधि को ओवरराइड करना पड़ा। कोड:

private class MyAdapter extends FragmentStatePagerAdapter {

    // [Rest of implementation]

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

}

1
इस एसओ जवाब में सब कुछ की कोशिश करने के बाद, यह वह है जो मेरे लिए काम करता है। मैं समाप्त कर रहा हूँ () एक गतिविधि है कि गतिविधि में वापस आ रहा है कि PagerAdapter मेजबान सवाल में आईएनजी। मैं चाहता हूं कि इस मामले में मेरे सभी टुकड़े फिर से बनाए जाएं क्योंकि जो गतिविधि मैंने अभी-अभी समाप्त की है, वह उस स्थिति को बदल सकती है जिसका उपयोग टुकड़ों को खींचने के लिए किया जाता है।
जॉनीलैम्बडा

OMG .. यह काम करता है .. यह काम करता है .. यश: D मेरे मामले में मुझे व्यूअर चालू वस्तु को हटाने की आवश्यकता है। लेकिन उपरोक्त सभी विधियों / चरणों को आज़माने के बाद वर्तमान टुकड़ा अपडेट नहीं हो रहा है।
राहुल खुराना

3

मैंने अपनी आवश्यकताओं के अनुरूप बिल फिलिप्स द्वारा प्रदान किए गए समाधान को थोड़ा संशोधित किया

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

ताकि केवल उन अंशों के लिए getItemPosition()रिटर्न POSITION_NONEजो वर्तमान में FragmentManagerजब getItemPositionकहा जाता है। (ध्यान दें कि यह FragmentStatePagerऔर ViewPagerइसके साथ जुड़े एक गतिविधि में नहीं एक टुकड़ा में निहित हैं)


2

मुझे भी इसी तरह की समस्या थी लेकिन मौजूदा समाधानों (हार्ड कोडेड टैग नामों) पर भरोसा नहीं करना चाहती और मैं एम-वेजेह के समाधान के लिए काम नहीं कर सकी। यहाँ मेरा समाधान है:

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

इस समस्या से बचने के लिए मैंने झटपट लागू किया (ViewGroup, int) और अपनी सरणी को इस तरह अद्यतन करें:

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

इसलिए, एक तरफ मैं खुश हूं कि मुझे एक समाधान मिला जो मेरे लिए काम करता है और इसे आपके साथ साझा करना चाहता था, लेकिन मैं यह भी पूछना चाहता था कि क्या किसी और ने भी कुछ इसी तरह की कोशिश की है और क्या कोई कारण है कि मुझे नहीं करना चाहिए क्या ऐसा है? अब तक यह मेरे लिए बहुत अच्छा काम करता है ...


मैंने stackoverflow.com/a/23427215/954643 से संबंधित कुछ किया है , हालाँकि आपको शायद आइटम को myFragmentsअंदर से भी निकाल देना चाहिए public void destroyItem(ViewGroup container, int position, Object object)ताकि आप एक बासी घर्षण संदर्भ को न पकड़ें।
क्िक्स

1

मैं सामग्री को अपडेट करने के लिए EventBus लाइब्रेरी का उपयोग करता हूं । तर्क सरल है, बस EventBus के दस्तावेज़ की तरह कैसे करना है । इसे उदाहरण पर नियंत्रण करने की कोई आवश्यकता नहीं है । कोड यहाँ है:FragmentViewPagerFragmentPagerAdapter

1: घटनाओं को परिभाषित करें

जो संदेश अद्यतन करने के लिए आवश्यक है उसे परिभाषित करें।

public class UpdateCountEvent {
    public final int count;

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

2. ग्राहक की सदस्यता लें

फ्रेगमेंट में नीचे दिए गए कोड को लिखें जिसे अपडेट की आवश्यकता है।

@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 घटनाओं

नीचे दिए गए कोड को अन्य Activityया अन्य में लिखें Fragmentजो पैरामीटर को अपडेट करने की आवश्यकता है

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

1

यदि आप FragmentStatePagerAdapter का उपयोग करना चाहते हैं, तो कृपया https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec-ID%20Type%20Status%20Owner%20Summary% पर एक नज़र डालें। 20Stars और GroupBy = & प्रकार = & id = 37,990 । FragmentStatePagerAdapter के साथ समस्याएं हैं जो आपके उपयोग के मामले को परेशान कर सकती हैं या नहीं कर सकती हैं।

इसके अलावा, लिंक के पास कुछ समाधान भी हैं..यदि आपकी आवश्यकता के अनुरूप हो सकता है।


उस URL से मुझे समाधान मिला। मैंने अपने कोड में इस gist.github.com/ypresto/8c13cb88a0973d071a64 से संशोधित FragmentStatePagerAdapter का उपयोग किया और यह माना जाने लगा कि यह काम करना शुरू कर दिया है।
राफेल

ठंडा। हाँ। लिंक के भी कुछ उपाय हैं।
CGR

1

मैंने एक ही समस्या को जीया है और मैंने बहुत बार खोजा है। स्टैकओवरफ़्लो में या Google के माध्यम से दिया गया कोई भी उत्तर मेरी समस्या का समाधान नहीं था। मेरी समस्या आसान थी। मेरे पास एक सूची है, मैं इस सूची को देखने वाले के साथ दिखाता हूं। जब मैं सूची के प्रमुख में एक नया तत्व जोड़ता हूं और मैं देखे गए दृश्य नोटिंग्स को बदल देता हूं। मेरा अंतिम समाधान बहुत आसान था जिसे कोई भी उपयोग कर सकता है। जब एक नया तत्व सूची में जोड़ा गया और सूची को ताज़ा करना चाहते हैं। सबसे पहले viewpager एडॉप्टर को null करने के लिए सेट करें फिर एडेप्टर को फिर से बनाएँ और i to viewpager पर सेट करें।

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

सुनिश्चित करें कि आपका एडेप्टर FragmentStatePagerAdapter का विस्तार करना चाहिए


1

यहाँ मेरा कार्यान्वयन है जो @Bill फिलिप्स से जानकारी को शामिल करता है एक को ज्यादातर कैशिंग के टुकड़े मिलते हैं, सिवाय इसके कि जब डेटा बदल गया है। सरल, और ठीक काम करने लगता है।

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

मैं कई अलग-अलग तरीकों की कोशिश कर रहा था, कोई भी वास्तव में मेरी समस्या को दूर नहीं करता है। नीचे मैं आप सभी द्वारा प्रदान किए गए समाधानों के मिश्रण के साथ इसे हल करता हूं। सभी को धन्यवाद।

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

मैं केवल पेज 0 पर पुन: चालू करना चाहता हूं ()।

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

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

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

मेरे FragmentsMain में, सार्वजनिक पूर्णांक "पृष्ठ" है, जो मुझे बता सकता है कि क्या यह वह पृष्ठ है जिसे मैं ताज़ा करना चाहता हूँ।

public class FragmentsMain extends Fragment {

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

0

मुझे पता है कि पार्टी के लिए देर हो चुकी है। मैंने TabLayout#setupWithViewPager(myViewPager);बस फोन करके समस्या को ठीक कर दिया हैFragmentPagerAdapter#notifyDataSetChanged();


0

यह समाधान सभी के लिए काम नहीं करेगा, लेकिन मेरे मामले में, मेरे ViewPager में प्रत्येक Fragment एक अलग वर्ग है, और उनमें से केवल एक ही समय में मौजूद है।

इस बाधा के साथ, यह समाधान सुरक्षित है और उत्पादन में उपयोग करने के लिए सुरक्षित होना चाहिए।

private void updateFragment(Item item) {

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

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

    }
}

यदि आपके पास एक ही टुकड़े के कई संस्करण हैं, तो आप उन अंशों पर कॉल करने के तरीकों को निर्धारित करने के लिए इस एक ही रणनीति का उपयोग कर सकते हैं यदि यह वह टुकड़ा है जिसे आप अपडेट करना चाहते हैं।


0

यह किसी की मदद के लिए हो सकता है - मेरे मामले में जब एक नया पृष्ठ सम्मिलित करते समय दृश्य पेजर एक मौजूदा टुकड़े की स्थिति के लिए दो बार पूछ रहा था, लेकिन नए आइटम की स्थिति के लिए नहीं पूछ रहा है, जिससे गलत व्यवहार और डेटा प्रदर्शित नहीं हो रहा है।

  1. FragmentStatePagerAdapter के लिए स्रोत की प्रतिलिपि बनाएँ (लगता है कि उम्र में अद्यतन नहीं किया गया है)।

  2. ओवरराइड सूचित करेंडेटासेटचेनड ()

    @Override
    public void notifyDataSetChanged() {
        mFragments.clear();
        super.notifyDataSetChanged();
    }
  3. दुर्घटनाओं को रोकने के लिए itItem () को संन्यास की जाँच जोड़ें:

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

0

मैं ऊपर दिए गए सभी उत्तरों और कई अन्य पोस्टों के माध्यम से जा चुका हूं, लेकिन अभी भी कुछ ऐसा नहीं मिला है जो मेरे लिए काम किया हो (अलग-अलग टुकड़े के साथ गतिशील रूप से जोड़ने और हटाने के साथ)। एफडब्ल्यूआईडब्ल्यू निम्नलिखित दृष्टिकोण है जो मेरे लिए काम करता है (यदि किसी और के पास समान मुद्दे हैं)।

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

यदि आप फ़्रेगमेंट पेजर एडेप्टर के बजाय FragmentStatePagerAdapter का उपयोग करना चाहते हैं, तो यदि आप अनुक्रमणिका के आधार पर खंड को फिर से बनाना या पुनः लोड करना चाहते हैं, उदाहरण के लिए यदि आप FirstFragment के अलावा किसी अन्य खंड को फिर से लोड करना चाहते हैं, तो आप उदाहरण की जाँच कर सकते हैं और इस तरह वापस आ सकते हैं

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

0

आपको तुरंत बदलाव की आवश्यकता है। mFragments तत्व getItemPosition।

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

आधारित AndroidX FragmentStatePagerAdapter.java, क्योंकि InformDataSetChanged mFragments() कॉल करते समय तत्वों की स्थिति नहीं बदलती है।

स्रोत: https://github.com/cuichanghao/infivt/blob/master/library/src/main/java/cc/cuichanghao/library/FragmentStatePagerChangelAdapter.java

उदाहरण: https://github.com/cuichanghao/infivt/blob/master/app/src/main/java/cc/cuichanghao/infivt/MainActivityChangeable/ager

कैसे काम करना है, इसकी पुष्टि के लिए आप इस प्रोजेक्ट को चला सकते हैं। https://github.com/cuichanghao/infivt

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.