android - गतिशील रूप से ViewPager अद्यतन करें?




android-fragments android-viewpager (12)

मैं ViewPager में सामग्री को अद्यतन नहीं कर सकता।

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

मैं अपने टुकड़ों को तुरंत चालू करने और वापस करने के लिए केवल getItem () का उपयोग कर रहा था:

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

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

तो मैंने यह पाया: ViewPager पेजर एडाप्टर दृश्य को अपडेट नहीं कर रहा है

विशेष रूप से जिसमें यह विधि तत्काल इटिम () के बारे में बात की जाती है:

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

तो अब मैं इसे करने के लिए instantiateItem () को कार्यान्वित करना चाहता हूं। लेकिन मुझे नहीं पता कि मुझे वहां क्या लौटना है (वापसी वस्तु है) और getItem (int position) के साथ संबंध क्या है?

वर्तमान में मैं फ्रेटमेंट को तुरंत चालू करने के लिए getItem का उपयोग कर रहा हूं, क्या यह गलत है? लेकिन फिर मुझे टुकड़ों को आवृत्ति चर में रखना होगा, या getItem () को लागू नहीं करना चाहिए ...? मैं बस इसे समझ में नहीं आता।

मैंने reference पढ़ने की कोशिश की:

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

    निर्दिष्ट स्थिति से जुड़े टुकड़े को वापस करें।

  • सार्वजनिक ऑब्जेक्ट तत्काल इटिम (व्यू ग्रुप कंटेनर, int स्थिति)

    दी गई स्थिति के लिए पेज बनाएँ। एडाप्टर यहां दिए गए कंटेनर को दृश्य जोड़ने के लिए ज़िम्मेदार है, हालांकि इसे केवल यह सुनिश्चित करना होगा कि यह FinUpdate (ViewGroup) से लौटाए जाने तक किया जाता है। पैरामीटर

    कंटेनर युक्त दृश्य जिसमें पृष्ठ दिखाया जाएगा। स्थिति पृष्ठ स्थिति तत्काल होना चाहिए।

    रिटर्न

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

... लेकिन मुझे अभी भी समझ में नहीं आता कि वे कैसे संबंधित हैं और मुझे क्या करना है।

मेरा कोड यहाँ है। मैं समर्थन पैकेज 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;
    }
}

यहां एक ही समस्या के साथ कोई भी है, कोई जवाब नहीं ...

http://www.mail-archive.com/[email protected]/msg200477.html


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

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

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

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

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

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

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

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

यदि आपको बेहतर प्रदर्शन की आवश्यकता है, तो आप एक 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 एक टुकड़े को नष्ट नहीं करता है इसका मतलब यह नहीं है कि GetMtemPosition एक FragmentPagerAdapter में पूरी तरह बेकार है। आप अभी भी ViewPager में अपने टुकड़े को पुन: व्यवस्थित करने के लिए इस कॉलबैक का उपयोग कर सकते हैं। हालांकि, यह उन्हें FragmentManager से पूरी तरह से कभी नहीं हटाएगा।


अपने कोड destroyDrawingCache() को destroyDrawingCache() बाद ViewPager पर destroyDrawingCache() करें destroyDrawingCache() को आज़माएं।


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

1- ऊपर वर्णित अनुसार आपको FragmentStatePagerAdapter का उपयोग करना होगा।

2-मुख्य एक्टिविटी पर मैं ऑनस्यूम को ओवरराइड करता हूं और निम्न करता हूं

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

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

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

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


किसी कारण से मेरे लिए कोई भी जवाब काम नहीं करता था इसलिए मुझे अपने खंड में सुपर कॉल किए बिना पुनर्स्थापना विधि को ओवरराइड करना थाStatePagerAdapter। कोड:

private class MyAdapter extends FragmentStatePagerAdapter {

    // [Rest of implementation]

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

}

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

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

इस समस्या से बचने के लिए मैंने तत्काल इटिम (व्यू ग्रुप, 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;
    }

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


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


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

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

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

public class FragmentsMain extends Fragment {

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

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

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

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

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 एक गतिविधि में नहीं है एक टुकड़ा में निहित हैं)


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

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


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

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

private void updateFragment(Item item) {

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

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

    }
}

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


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

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




android-viewpager