android - ViewPager PagerAdapter दृश्य को अपडेट नहीं कर रहा है




android-viewpager (20)

Rui.araujo और अल्वारो लुइस Bustamante धन्यवाद। सबसे पहले, मैं rui.araujo के तरीके का उपयोग करने की कोशिश करता हूं, क्योंकि यह आसान है। यह काम करता है लेकिन जब डेटा बदलता है, पृष्ठ स्पष्ट रूप से फिर से चला जाएगा। यह बुरा है इसलिए मैं अल्वारो लुइस बुस्टामेंटे के रास्ते का उपयोग करने की कोशिश करता हूं। यह एकदम सही है। यहां कोड है:

@Override
protected void onStart() {
    super.onStart();
}

private class TabPagerAdapter extends PagerAdapter {
    @Override
    public int getCount() {
        return 4;
    }

    @Override
    public boolean isViewFromObject(final View view, final Object object) {
        return view.equals(object);
    }

    @Override
    public void destroyItem(final View container, final int position, final Object object) {
        ((ViewPager) container).removeView((View) object);
    }

    @Override
    public Object instantiateItem(final ViewGroup container, final int position) {
        final View view = LayoutInflater.from(
                getBaseContext()).inflate(R.layout.activity_approval, null, false);
        container.addView(view);
        ListView listView = (ListView) view.findViewById(R.id.list_view);
        view.setTag(position);
        new ShowContentListTask(listView, position).execute();
        return view;
    }
}

और जब डेटा बदलता है:

for (int i = 0; i < 4; i++) {
    View view = contentViewPager.findViewWithTag(i);
    if (view != null) {
        ListView listView = (ListView) view.findViewById(R.id.list_view);
        new ShowContentListTask(listView, i).execute();
    }
}

मैं संगतता पुस्तकालय से ViewPager का उपयोग कर रहा हूँ। मैंने सफलतापूर्वक इसे कई विचार प्रदर्शित किए हैं जिन्हें मैं पेज कर सकता हूं।

हालांकि, मुझे एक नए समय के दृश्य के साथ ViewPager को अद्यतन करने का तरीका समझने में कठिनाई हो रही है।

मैंने mAdapter.notifyDataSetChanged() , mViewPager.invalidate() कॉल करने जैसे सभी प्रकार की चीजों की कोशिश की है, हर बार जब मैं डेटा की एक नई सूची का उपयोग करना चाहता हूं तो एक नया नया एडाप्टर भी बना सकता हूं।

कुछ भी मदद नहीं मिली है, टेक्स्टव्यू मूल डेटा से अपरिवर्तित रहते हैं।

अपडेट करें: मैंने थोड़ा परीक्षण प्रोजेक्ट बनाया है और मैं लगभग विचारों को अपडेट करने में सक्षम हूं। मैं नीचे वर्ग पेस्ट करूँगा।

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

public class ViewPagerBugActivity extends Activity {

    private ViewPager myViewPager;
    private List<String> data;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        data = new ArrayList<String>();
        data.add("A");
        data.add("B");
        data.add("C");

        myViewPager = (ViewPager) findViewById(R.id.my_view_pager);
        myViewPager.setAdapter(new MyViewPagerAdapter(this, data));

        Button updateButton = (Button) findViewById(R.id.update_button);
        updateButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                updateViewPager();
            }
        });
    }

    private void updateViewPager() {
        data.clear();
        data.add("X");
        data.add("Y");
        data.add("Z");
        myViewPager.getAdapter().notifyDataSetChanged();
    }

    private class MyViewPagerAdapter extends PagerAdapter {

        private List<String> data;
        private Context ctx;

        public MyViewPagerAdapter(Context ctx, List<String> data) {
            this.ctx = ctx;
            this.data = data;
        }

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

        @Override
        public Object instantiateItem(View collection, int position) {
            TextView view = new TextView(ctx);
            view.setText(data.get(position));
            ((ViewPager)collection).addView(view);
            return view;
        }

        @Override
        public void destroyItem(View collection, int position, Object view) {
             ((ViewPager) collection).removeView((View) view);
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public Parcelable saveState() {
            return null;
        }

        @Override
        public void restoreState(Parcelable arg0, ClassLoader arg1) {
        }

        @Override
        public void startUpdate(View arg0) {
        }

        @Override
        public void finishUpdate(View arg0) {
        }
    }
}

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

फिर, CustomViewPager में, UpdateViewAt (int स्थिति) नामक एक विधि बनाएं। दृश्य स्वयं को ViewPager क्लास में परिभाषित ArrayList mItems से प्राप्त किया जा सकता है (आपको तत्काल आइटम पर विचारों के लिए एक आईडी सेट करने की आवश्यकता है और UpdateViewAt () विधि में स्थिति के साथ इस आईडी की तुलना करें)। फिर आप आवश्यकतानुसार दृश्य को अपडेट कर सकते हैं।


आप गतिशील रूप से सभी टुकड़े अपडेट कर सकते हैं, आप तीन चरणों में देख सकते हैं।

आपके एडाप्टर में:

public class MyPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 3;
private Map<Integer, String> mFragmentTags;
private FragmentManager mFragmentManager;

public MyPagerAdapter(FragmentManager fragmentManager) {
    super(fragmentManager);
    mFragmentManager = fragmentManager;
    mFragmentTags = new HashMap<Integer, String>();
}

// Returns total number of pages
@Override
public int getCount() {
    return NUM_ITEMS;
}

// Returns the fragment to display for that page
@Override
public Fragment getItem(int position) {
    switch (position) {
        case 0:
            return FirstFragment.newInstance();
        case 1:
            return SecondFragment.newInstance();
        case 2:
            return ThirdFragment.newInstance();
        default:
            return null;
    }
}

// Returns the page title for the top indicator
@Override
public CharSequence getPageTitle(int position) {
    return "Page " + position;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object object = super.instantiateItem(container, position);
    if (object instanceof Fragment) {
        Fragment fragment = (Fragment) object;
        String tag = fragment.getTag();
        mFragmentTags.put(position, tag);
    }
    return object;
}

public Fragment getFragment(int position) {
    Fragment fragment = null;
    String tag = mFragmentTags.get(position);
    if (tag != null) {
        fragment = mFragmentManager.findFragmentByTag(tag);
    }
    return fragment;
}}

अब आपकी गतिविधि में:

public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener{

MyPagerAdapter mAdapterViewPager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ViewPager viewPager = (ViewPager) findViewById(R.id.vpPager);
    mAdapterViewPager = new MyPagerAdapter(getSupportFragmentManager());
    viewPager.setAdapter(mAdapterViewPager);
    viewPager.addOnPageChangeListener(this);
}

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

}

@Override
public void onPageSelected(int position) {

    Fragment fragment = mAdapterViewPager.getFragment(position);
    if (fragment != null) {
        fragment.onResume();
    }
}

@Override
public void onPageScrollStateChanged(int state) {

}}

अंत में आपके टुकड़े में, ऐसा कुछ:

public class YourFragment extends Fragment {

// newInstance constructor for creating fragment with arguments
public static YourFragment newInstance() {

    return new YourFragment();
}

// Store instance variables based on arguments passed
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

// Inflate the view for the fragment based on layout XML
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment, container, false);
}


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

    //to refresh your view
    refresh();

}}

आप here पूरा कोड देख सकते हैं।

धन्यवाद अलवरो लुइस बुस्टामेंटे।


इन सभी समाधानों ने मेरी मदद नहीं की। इस प्रकार मुझे एक कामकाजी समाधान मिला: आप हर बार setAdapter कर सकते हैं, लेकिन यह पर्याप्त नहीं है। एडाप्टर बदलने से पहले आपको इन्हें करना चाहिए:

FragmentManager fragmentManager = slideShowPagerAdapter.getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
List<Fragment> fragments = fragmentManager.getFragments();
for (Fragment f : fragments) {
    transaction.remove(f);
}
transaction.commit();

और उसके बाद:

viewPager.setAdapter(adapter);

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

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 के निर्माता को मेरी class में इसे संग्रहीत करने के लिए मेरा FragmentManager इंस्टेंस ले लो:

private FragmentManager mFragmentManager;
private ArrayList<PagerItem> mPagerItems;

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

4) नए डेटा के साथ adapter डेटा को फिर से सेट करने के लिए एक विधि बनाएं, fragment से सभी पिछले fragment को हटाकर सीधे 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();

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


इसे प्राप्त करने के कई तरीके हैं।

पहला विकल्प आसान है, लेकिन थोड़ा अधिक अक्षम है।

अपने getItemPosition में getItemPosition को ओवरराइड करें:

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

इस तरह, जब आप notifyDataSetChanged() कॉल करते हैं, तो दृश्य पेजर सभी दृश्यों को हटा देगा और उन सभी को पुनः लोड करेगा। इसलिए रीलोड प्रभाव प्राप्त होता है।

दूसरा विकल्प, अल्वरो लुइस बस्टामेंटे (पहले अल्वरोलब) द्वारा सुझाया गया है , एक नया दृश्य instantiateItem() करने पर instantiateItem() setTag() विधि है। फिर findViewWithTag() को findViewWithTag() करने के बजाय, आप जिस दृश्य को अपडेट करना चाहते हैं उसे ढूंढने के लिए findViewWithTag() का उपयोग कर सकते हैं।

दूसरा दृष्टिकोण बहुत लचीला और उच्च प्रदर्शनकारी है। मूल शोध के लिए अलवरोल को कुडोस।


एक ही समस्या थी। मेरे लिए यह FragmentStatePagerAdapter को बढ़ाने के लिए काम करता है, और नीचे दिए गए तरीकों को ओवरराइड करता है:

@Override
public Parcelable saveState() {
    return null;
}

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

}

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

मेरे टुकड़े में (पेज):

  • मैंने सभी कोड ले लिए जो क्रिएटिव्यू पर फॉर्म को पॉप्युलेट करते हैं और इसे पॉप्युलेटफॉर्म नामक एक फ़ंक्शन में डालते हैं जिसे फ्रेमवर्क के बजाए कहीं से भी कहा जा सकता है। यह फ़ंक्शन getView का उपयोग करके वर्तमान दृश्य प्राप्त करने का प्रयास करता है, और यदि यह शून्य है, तो यह अभी लौटाता है। यह महत्वपूर्ण है कि पॉप्युलेटफॉर्म में केवल वह कोड होता है जो प्रदर्शित करता है - अन्य सभी कोड जो फोकस चेंज श्रोताओं को बनाता है और जैसा कि अभी भी ऑनक्रेट में है
  • एक बूलियन बनाएं जिसका उपयोग ध्वज के रूप में किया जा सकता है जो दर्शाता है कि फ़ॉर्म को फिर से लोड किया जाना चाहिए। मेरा mbReloadForm है
  • PopulateForm () को कॉल करने के लिए OnResume () को ओवरराइड करें यदि mbReloadForm सेट है।

मेरी गतिविधि में, जहां मैं पृष्ठों की लोडिंग करता हूं:

  • कुछ भी बदलने से पहले पेज 0 पर जाएं। मैं FragmentStatePagerAdapter का उपयोग कर रहा हूं, इसलिए मुझे पता है कि अधिकतर दो या तीन पृष्ठ प्रभावित होते हैं। पृष्ठ 0 में बदलना सुनिश्चित करता है कि मुझे केवल पृष्ठ 0, 1 और 2 पर समस्या है।
  • पुरानी सूची को साफ़ करने से पहले, इसका आकार लें ()। इस तरह आप जानते हैं कि बग द्वारा कितने पेज प्रभावित होते हैं। यदि> 3, इसे 3 तक कम करें - यदि आप एए अलग पेजर एडाप्टर का उपयोग कर रहे हैं, तो आपको देखना होगा कि आपको कितने पेजों से निपटना है (शायद सभी?)
  • डेटा को दोबारा लोड करें और पेज पर कॉल करेंएडाप्टर। नोटिफाइडडेटासेट चेंज ()
  • अब, प्रत्येक प्रभावित पृष्ठों के लिए, देखें कि पृष्ठ पेजर.getChildAt (i) का उपयोग करके सक्रिय है या नहीं - यह आपको बताता है कि क्या आपके पास कोई दृश्य है। यदि ऐसा है, तो पेजर को कॉल करें। PopulateView ()। यदि नहीं, तो ReloadForm ध्वज सेट करें।

इसके बाद, जब आप पृष्ठों का दूसरा सेट पुनः लोड करते हैं, तो बग अभी भी पुराने डेटा को प्रदर्शित करने का कारण बनता है। हालांकि, वे अब ताज़ा हो जाएंगे और आपको नया डेटा दिखाई देगा - आपके उपयोगकर्ता नहीं जानते कि पृष्ठ कभी भी गलत था क्योंकि पेज को देखने से पहले यह ताज़ा होगा।

उम्मीद है कि यह किसी की मदद करता है!


मुझे इस समस्या का बहुत ही दिलचस्प निर्णय मिला। FragmentPagerAdapter का उपयोग करने के बजाय, जो सभी टुकड़ों को स्मृति में रखता है, हम FragmentStatePagerAdapter ( android.support.v4.app.FragmentStatePagerAdapter ) का उपयोग कर सकते हैं, जब हम इसे चुनते हैं तो हर बार खंड को फिर से लोड करें।

दोनों एडाप्टर की प्राप्तियां समान हैं। इसलिए, हमें " FragmentStatePagerAdapter का विस्तार " पर केवल " FragmentPagerAdapter का विस्तार करें " को बदलने की आवश्यकता है


मुझे एक ऐसी ही समस्या थी जिसमें मेरे चार पृष्ठ थे और पृष्ठों में से एक ने अन्य तीनों पर विचारों को अपडेट किया था। मैं वर्तमान पृष्ठ के समीप पृष्ठ पर विजेट (सेकबार्स, टेक्स्ट व्यू इत्यादि) को अपडेट करने में सक्षम था। mTabsAdapter.getItem(position) कॉल करते समय पिछले दो पृष्ठों में mTabsAdapter.getItem(position) विजेट होंगे।

मेरी समस्या को हल करने के लिए, मैंने getItem(position) कॉल करने से पहले setSelectedPage(index) उपयोग किया। यह पृष्ठ को तुरंत चालू करेगा, जिससे मैं प्रत्येक पृष्ठ पर मूल्यों और विजेटों को बदलने में सक्षम हो सकता हूं।

अद्यतन करने के बाद मैं setSelectedPage(position) उपयोग करता हूं, इसके setSelectedPage(position) हूं।

आप मुख्य अद्यतन पृष्ठ पर ListView में थोड़ा झिलमिलाहट देख सकते हैं, लेकिन कुछ भी ध्यान देने योग्य नहीं है। मैंने इसका परीक्षण नहीं किया है, लेकिन यह मेरी तत्काल समस्या का समाधान करता है।


मुझे लगता है, मुझे ViewPager का तर्क मिला है।

अगर मुझे पृष्ठों के एक सेट को ताज़ा करने और उन्हें नए डेटासेट के आधार पर प्रदर्शित करने की आवश्यकता है, तो मैं सूचित करता हूंडेटाडेट चेंज () । फिर, ViewPager एक ऑब्जेक्ट के रूप में फ्रैगमेंट पास करने के लिए ItemPosition () प्राप्त करने के लिए कई कॉल करता है। यह टुकड़ा या तो पुराने डेटासेट (जिसे मैं त्यागना चाहता हूं) या एक नए से (जिसे मैं प्रदर्शित करना चाहता हूं) से हो सकता हूं। इसलिए, मैं getItemPosition () को ओवरराइड करता हूं और वहां मुझे किसी भी तरह का निर्धारण करना होगा यदि मेरा टुकड़ा पुराने डेटासेट से या नए से है।

मेरे मामले में मेरे पास बाएं फलक पर शीर्ष आइटमों की एक सूची और दाईं ओर एक स्वाइप व्यू (व्यूपेजर) के साथ 2-फलक लेआउट है। इसलिए, मैं अपने वर्तमान शीर्ष आइटम को मेरे पेजर एडाप्टर के अंदर और प्रत्येक तत्काल पृष्ठ फ्रैगमेंट के अंदर भी एक लिंक स्टोर करता हूं। जब सूची में चयनित शीर्ष आइटम बदलता है, तो मैं पेजर एडाप्टर में नया शीर्ष आइटम संग्रहीत करता हूं औरडेटाडेटांग () को सूचित करता हूं। और ओवरराइड getItemPosition () में मैं अपने एडाप्टर से शीर्ष आइटम की तुलना अपने टुकड़े से शीर्ष आइटम की तुलना करता हूं। और केवल अगर वे बराबर नहीं हैं, तो मैं POSITION_NONE लौटाता हूं। फिर, पेजर एडाप्टर POSITION_NONE लौटाए गए सभी टुकड़ों को पुन: स्थापित करता है।

ध्यान दें। किसी संदर्भ के बजाय शीर्ष आइटम आईडी संग्रहीत करना एक बेहतर विचार हो सकता है।

नीचे कोड स्निपेट थोड़ा सा स्केमैटिकल है लेकिन मैंने इसे वास्तव में काम करने वाले कोड से अनुकूलित किया है।

public class SomeFragment extends Fragment {
  private TopItem topItem;
}

public class SomePagerAdapter extends FragmentStatePagerAdapter {
  private TopItem topItem;

  public void changeTopItem(TopItem newTopItem) {
    topItem = newTopItem;
    notifyDataSetChanged();
  }

  @Override
  public int getItemPosition(Object object) {
    if (((SomeFragment) object).getTopItemId() != topItem.getId()) {
      return POSITION_NONE;
    }
    return super.getItemPosition(object);
  }
}

Thanks for all the previous researchers!


मेरे पास एक ही समस्या थी और मेरा समाधान ViewPagerAdapter#getItemId(int position) से ओवरराइड कर रहा है:

@Override
public long getItemId(int position) {
    return mPages.get(position).getId();
}

डिफ़ॉल्ट रूप से, यह विधि आइटम की स्थिति लौटाती है। मुझे लगता है कि ViewPager जांचता है कि itemId बदला गया था और केवल तभी पृष्ठ को पुन: प्रयास करता है। लेकिन itemId -ओवर्रिडेन संस्करण itemId के समान स्थिति देता है, भले ही पृष्ठ वास्तव में अलग है, और ViewPager यह परिभाषित नहीं करता है कि उस पृष्ठ को प्रतिस्थापित किया गया है और उसे पुनर्निर्मित करने की आवश्यकता है।

इसका उपयोग करने के लिए, प्रत्येक पृष्ठ के लिए long id की आवश्यकता होती है। आम तौर पर यह अद्वितीय होने की उम्मीद है, लेकिन मैं सुझाव देता हूं कि, इस मामले के लिए, यह एक ही पृष्ठ के पिछले मान से अलग होना चाहिए। इसलिए, एडाप्टर या यादृच्छिक पूर्णांक (विस्तृत वितरण के साथ) में निरंतर काउंटर का उपयोग करना संभव है।

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


यह एक भयानक समस्या है और मुझे एक उत्कृष्ट समाधान पेश करने में खुशी है; सरल, कुशल और प्रभावी!

नीचे देखें, कोड ध्वज का उपयोग करके दिखाता है कि यह इंगित करने के लिए कि POSITION_NONE कब वापस आना है

public class ViewPagerAdapter extends PagerAdapter
{
    // Members
    private boolean mForceReinstantiateItem = false;

    // This is used to overcome terrible bug that Google isn't fixing
    // We know that getItemPosition() is called right after notifyDataSetChanged()
    // Therefore, the fix is to return POSITION_NONE right after the notifyDataSetChanged() was called - but only once
    @Override
    public int getItemPosition(Object object)
    {
        if (mForceReinstantiateItem)
        {
            mForceReinstantiateItem = false;
            return POSITION_NONE;
        }
        else
        {
            return super.getItemPosition(object);
        }
    }

    public void setData(ArrayList<DisplayContent> newContent)
    {
        mDisplayContent = newContent;
        mForceReinstantiateItem = true;
        notifyDataSetChanged();
    }

}

हमेशा POSITION_NONE लौटने पर सरल होता है लेकिन थोड़ा अक्षम तरीका होता है क्योंकि इससे पहले से ही सभी पेजों की तत्कालता उत्पन्न होती है।

मैंने गतिशील रूप से पेजरएडाप्टर में आइटम बदलने के लिए एक लाइब्रेरी ArrayPagerAdapter बनाया है।

आंतरिक रूप से, इस लाइब्रेरी के एडेप्टर केवल जब आवश्यक हो तो getItemPosiition() पर POSITION_NONE getItemPosiition()

आप इस पुस्तकालय का उपयोग करके गतिशील रूप से निम्न वस्तुओं को बदल सकते हैं।

@Override
protected void onCreate(Bundle savedInstanceState) {
        /** ... **/
    adapter = new MyStatePagerAdapter(getSupportFragmentManager()
                            , new String[]{"1", "2", "3"});
    ((ViewPager)findViewById(R.id.view_pager)).setAdapter(adapter);
     adapter.add("4");
     adapter.remove(0);
}

class MyPagerAdapter extends ArrayViewPagerAdapter<String> {

    public MyPagerAdapter(String[] data) {
        super(data);
    }

    @Override
    public View getView(LayoutInflater inflater, ViewGroup container, String item, int position) {
        View v = inflater.inflate(R.layout.item_page, container, false);
        ((TextView) v.findViewById(R.id.item_txt)).setText(item);
        return v;
    }
}

थिल्स लाइब्रेरी फ्रैगमेंट्स द्वारा बनाए गए पृष्ठों का भी समर्थन करती है।


FragmentPagerAdapter को FragmentStatePagerAdapter बदलें।

getItemPosition() विधि को ओवरराइड करें और POSITION_NONE वापस करें।

आखिरकार, यह पेजर देखने पर notifyDataSetChanged() को सुन देगा।


For what it's worth, on KitKat+ it seems that adapter.notifyDataSetChanged() is enough to cause the new views to show up, provided that you've setOffscreenPageLimit sufficiently high. I'm able to get desired behavior by doing viewPager.setOffscreenPageLimit(2) .


I have tried all this solutions did not work for me because all my views are complex. So it is difficult to save the View and update the View. If you have a simple View that contains only a few TextView or something like this, it's easy and the solutions posted here works. But if you have complex View like mine, and need to change the entire Fragment, I think that's impossible to do. I have investigating the ViewPager code, and it seems that the ViewPager keeps the old fragments. It's easy to realize it : Search for some native application from your device that implements swipe and do the test changing the language from English to Arabic. In this case, it should change the order of fragments, because Arabic is a RTL language. But it did not work this way.


I m using Tablayout with ViewPagerAdapter. For passing data between fragments or for communicating between fragments use below code which works perfectly fine and refresh the fragment when ever it appears. Inside button click of second fragment write below code.

b.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            String text=e1.getText().toString(); // get the text from EditText

            // move from one fragment to another fragment on button click
            TabLayout tablayout = (TabLayout) getActivity().findViewById(R.id.tab_layout); // here tab_layout is the id of TabLayout which is there in parent Activity/Fragment
            if (tablayout.getTabAt(1).isSelected()) { // here 1 is the index number of second fragment i-e current Fragment

                LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
                Intent i = new Intent("EDIT_TAG_REFRESH");
                i.putExtra("MyTextValue",text);
                lbm.sendBroadcast(i);

            }
            tablayout.getTabAt(0).select(); // here 0 is the index number of first fragment i-e to which fragment it has to moeve

        }
    });

below is the code which has to be written in first fragment (in my case) ie in receiving Fragment.

MyReceiver r;
Context context;
String newValue;
public void refresh() {
    //your code in refresh.
    Log.i("Refresh", "YES");
}
public void onPause() {
    super.onPause();

    LocalBroadcastManager.getInstance(context).unregisterReceiver(r);
}
public void onResume() {
    super.onResume();
    r = new MyReceiver();
    LocalBroadcastManager.getInstance(getActivity()).registerReceiver(r,
            new IntentFilter("EDIT_TAG_REFRESH"));
} // this code has to be written before onCreateview()


 // below code can be written any where in the fragment
 private class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
    PostRequestFragment.this.refresh();
        String action = intent.getAction();
        newValue=intent.getStringExtra("MyTextValue");
        t1.setText(newValue); // upon Referesh set the text
    }
}

In my case every time that Fragment entered to @override onCreateView(...) i was restarting values so handle null or empty values like:

if(var == null){
    var = new Something();
}

if(list.isEmpty()){
    list = new ArrayList<MyItem>();
}

if(myAdapter == null){
    myAdapter = new CustomAdapter();
    recyclerView.setAdapter(myAdapter);
}

// etc...

Fragment class could enter to onCreateView every time we change and get back to the view from the UI at runtime.






android-viewpager