Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update ViewPager dynamically?

I can't update the content in ViewPager.

What is the correct usage of methods instantiateItem() and getItem() in FragmentPagerAdapter class?

I was using only getItem() to instantiate and return my fragments:

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

This worked well. Except I can't change the content.

So I found this: ViewPager PagerAdapter not updating the View

"My approach is to use the setTag() method for any instantiated view in the instantiateItem() method"

Now I want to implement instantiateItem() to do that. But I don't know what I have to return (the type is Object) and what is the relation with getItem(int position)?

I read the reference:

  • public abstract Fragment getItem (int position)

    Return the Fragment associated with a specified position.

  • public Object instantiateItem (ViewGroup container, int position)

    Create the page for the given position. The adapter is responsible for adding the view to the container given here, although it only must ensure this is done by the time it returns from finishUpdate(ViewGroup). Parameters

    container The containing View in which the page will be shown. position The page position to be instantiated.

    Returns

    Returns an Object representing the new page. This does not need to be a View, but can be some other container of the page.

but I still don't get it.

Here's my code. I'm using support package 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;     } } 

Here is also somebody with a similar problem, no answers http://www.mail-archive.com/[email protected]/msg200477.html

like image 347
User Avatar asked Jun 01 '12 11:06

User


People also ask

How do I update my Android ViewPager adapter?

Firstly set viewpager adapter to null then recreate the adapter and set i to it to viewpager. Show activity on this post. Define which message which is needed to update. Write below code in the Fragment which is needed update.

How do I refresh ViewPager2?

As we already know that ViewPager2 is built on RecyclerView that's why it's easy to update only one item by calling the method notifyItemChanged(index). If we want to update all items then we can also do this by simply calling the notifyDatasetChanged() method. That's it for now.

How do I refresh Fragmentpageradapter?

You can use startActivityForResult(or broadcast/receiver) to get the result from the activity. Then use adapter. notifyDataSetChanged to refresh the fragment.

What is ViewPager2?

ViewPager2 is an improved version of the ViewPager library that offers enhanced functionality and addresses common difficulties with using ViewPager . If your app already uses ViewPager , read this page to learn more about migrating to ViewPager2 .


2 Answers

When using FragmentPagerAdapter or FragmentStatePagerAdapter, it is best to deal solely with getItem() and not touch instantiateItem() at all. The instantiateItem()-destroyItem()-isViewFromObject() interface on PagerAdapter is a lower-level interface that FragmentPagerAdapter uses to implement the much simpler getItem() interface.

Before getting into this, I should clarify that

if you want to switch out the actual fragments that are being displayed, you need to avoid FragmentPagerAdapter and use FragmentStatePagerAdapter.

An earlier version of this answer made the mistake of using FragmentPagerAdapter for its example - that won't work because FragmentPagerAdapter never destroys a fragment after it's been displayed the first time.

I don't recommend the setTag() and findViewWithTag() workaround provided in the post you linked. As you've discovered, using setTag() and findViewWithTag() doesn't work with fragments, so it's not a good match.

The right solution is to override getItemPosition(). When notifyDataSetChanged() is called, ViewPager calls getItemPosition() on all the items in its adapter to see whether they need to be moved to a different position or removed.

By default, getItemPosition() returns POSITION_UNCHANGED, which means, "This object is fine where it is, don't destroy or remove it." Returning POSITION_NONE fixes the problem by instead saying, "This object is no longer an item I'm displaying, remove it." So it has the effect of removing and recreating every single item in your adapter.

This is a completely legitimate fix! This fix makes notifyDataSetChanged behave like a regular Adapter without view recycling. If you implement this fix and performance is satisfactory, you're off to the races. Job done.

If you need better performance, you can use a fancier getItemPosition() implementation. Here's an example for a pager creating fragments off of a list of strings:

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

With this implementation, only fragments displaying new titles will get displayed. Any fragments displaying titles that are still in the list will instead be moved around to their new position in the list, and fragments with titles that are no longer in the list at all will be destroyed.

What if the fragment has not been recreated, but needs to be updated anyway? Updates to a living fragment are best handled by the fragment itself. That's the advantage of having a fragment, after all - it is its own controller. A fragment can add a listener or an observer to another object in onCreate(), and then remove it in onDestroy(), thus managing the updates itself. You don't have to put all the update code inside getItem() like you do in an adapter for a ListView or other AdapterView types.

One last thing - just because FragmentPagerAdapter doesn't destroy a fragment doesn't mean that getItemPosition is completely useless in a FragmentPagerAdapter. You can still use this callback to reorder your fragments in the ViewPager. It will never remove them completely from the FragmentManager, though.

like image 139
Bill Phillips Avatar answered Sep 21 '22 07:09

Bill Phillips


Instead of returning POSITION_NONE from getItemPosition() and causing full view recreation, do this:

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

Your fragments should implement UpdateableFragment interface:

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

and the interface:

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

Your data class:

public class UpdateData {     //whatever you want here } 
like image 40
M-WaJeEh Avatar answered Sep 20 '22 07:09

M-WaJeEh