I am using FragmentStatePagerAdapter in my app.
My problem is that when I am doing notifyDataSetChanged() it's calling only the getCount() and not the getItem(). the getCount is not returning 0.
this is my FragmentStatePagerAdapter:
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
return titles.get(position);
}
#Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
#Override
public int getCount() {
return fragmentList.size();
}
}
How could it be that after pagerAdapter.notifyDataSetChanged(); only the getCount() is called and the getItem(int position) is not being called after it?
Thanks!
From Issue 19001, I found that int getItemPosition(Object object) needs to be implemented in the FragmentStatePageAdapter subclass. By default this method is assumed to return POSITION_UNCHANGED which will not trigger getItem to be called. However, I, also, ran into issues (possible bugs in the android support library) when I implemented anything other than return POSITION_NONE.
Snippet from my adapter:
#Override
public Fragment getItem(int position) {
return DiceRollerFragment.instantiate(position);
}
Related
The mainActivity recovered, the fragment cannot be seen but the lifecycle is absolutely loading well.
mContainer.setAdapter(new FragmentPagerAdapter(activity.getSupportFragmentManager()) {
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
});
If you are doing this in a fragment, you must pass a childFragmentManager to the pager adapter.
mContainer.setAdapter(new FragmentPagerAdapter(***getChildFragmentManager()***) {
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
});
I use FragmentStatePagerAdapter to manage my ViewPager. I have overwritten "getItemPosition" function. Here is my code:
mViewPager.setAdapter(new FragmentStatePagerAdapter(fm) {
#Override
public Fragment getItem(int position) {
Crime c = mCrimes.get(position);
return CrimeFragment.newInstance(c.getmId());
}
#Override
public int getCount() {
return mCrimes.size();
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
});
But the problem is that when I delete the first fragment, the last fragment will be deleted, but others work well. I don't know why.
I am using ViewPager with fragments and a FragmentStatePagerAdapter, i need update my second fragment based on what the user checked in the first one, what happens is that both fragments are loaded when the fragment activity is started, so doesn't matter what the user checks on the first fragment, the second will not get updated. i've tried to override de getItemPosition with the notifyDataSetChanged for call a method to update my fragment, but it appears to be called just when it's created, i need update the second fragment when the user check the options that he want in the first fragment. Thanks
public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public ScreenSlidePagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
}
#Override
public Fragment getItem(int position) {
if(mFragments.get(position) instanceof UpdateableFragment){
notifyDataSetChanged();
}
return mFragments.get(position);
}
#Override
public int getCount() {
return mFragments.size();
}
#Override
public int getItemPosition(Object object) {
if (object instanceof UpdateableFragment) {
((UpdateableFragment) object).customize();
}
return super.getItemPosition(object);
}
}
I tried to do what the other answers suggested, but when I look at the logs, after getItemPosition is returned with POSITION_NONE, position 0 does not get called for getItem, any idea? I also tried to override destoryItem when getItemPosition is returned, it DOES get called but nothing happens.
public class ProvidersActivityPagerAdapter extends FragmentPagerAdapter {
private ArrayList<String> fragments;
public ProvidersActivityPagerAdapter(FragmentManager fm) {
super(fm);
fragments=new ArrayList<String>();
if(provider.isInitialized()){
fragments.add(BaseDetailsFragment.class.getName());
}else{
fragments.add(BaseAuthFragment.class.getName());
}
this.fm=fm;
}
#Override
public int getCount(){
return fragments.size();
}
#Override
public int getItemPosition(Object object) {
AppUtils.logI("Get Item Position: "+POSITION_NONE+" "+object.getClass().getName());
return POSITION_NONE;
}
#Override
public Fragment getItem(int position) {
AppUtils.logI("Get Fragment for: "+position);
String f=fragments.get(position);
if(f.equals(BaseDetailsFragment.class.getName())){
return provider.getDetailFragment();
}
if(f.equals(BaseAuthFragment.class.getName())){
return provider.getAuthFragment();
}
if(f.equals(BaseSelectorFragment.class.getName())){
return provider.getCurrentSelector();
}
return new Fragment();
}
private void addItem(int loc,String fa,String tag){
this.fragments.add(loc,fa);
AppUtils.logI(fragments.toString());
notifyDataSetChanged(); //only creates the new fragment but not updating the old ones.
mViewPager.setCurrentItem(loc);
}
It appears that the support library version of the FragmentPagerAdapter does NOTHING in destroy item. So the solution is to save the fragment manager when constructing the page adapter and override the destoryItem() function. Note that this may not be compatible to future editions of the support library.
#Override
public void destroyItem(ViewGroup container,int position,Object object){
super.destroyItem(container, position, object);
FragmentTransaction bt = fm.beginTransaction();
bt.remove((Fragment)object);
bt.commit();
}
I want to prepend a new View as first page of my ViewPager.
My adapter looks like this:
public class PagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> fragments;
public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int index) {
return fragments.get(index);
}
#Override
public int getCount() {
return fragments.size();
}
public void add(int i, ImageFileObject imageFile) {
ImageViewFragment f = new ImageViewFragment();
f.setImage(imageFile);
fragments.add(0, f);
notifyDataSetChanged();
}
public void add(ImageFileObject imageFile) {
ImageViewFragment f = new ImageViewFragment();
f.setImage(imageFile);
fragments.add(f);
notifyDataSetChanged();
}
}
But when calling add(0, aImageFile) the item is not prepended to the fragment list. (It's not even appended).
Any ideas?
Update: The problem that you described in comment is real, I missed it in first testing. After analyzing the source code of FragmentPagerAdapter I realized that all we need to do is to Override getItemId() in a way that it won't return same id for different fragment items. E.g. current default implementation would just return position as an id for fragment which won't work for this case:
public long getItemId(int position) {
return position;
}
I am updating this answer, please have a look. As before I have tested this code and the problem you described is not happening now.
Only thing you need is not to keep reference of fragments by yourself in List, This is done for you by FragmentPagerAdapter. And as far as I know its not a good practise either. And also even if you return POSITION_NONE from getItemPosition() as suggested by other answer(s), you will end up with Exception
Caused by: java.lang.IllegalStateException: Can't change tag of fragment.
This is because you are trying to reposition alive Fragments in your List by adding a fragment at 0th index (which causes other fragments to reposition) and ViewPager assigns tags based on position.
Keeping all this in mind, here is a tested and working modified adapter:
public class PagerAdapter extends FragmentPagerAdapter {
public static class FragmentInfo {
public String classz;
public ImageFileObject imageFile;
public static long IDS;
public long id;
public FragmentInfo(){
id = IDS++;
}
}
private final List<FragmentInfo> fragments;
private Context context;
public PagerAdapter(FragmentManager fm, List<FragmentInfo> fragments,
Context context) {
super(fm);
this.fragments = fragments;
this.context = context;
}
#Override
public Fragment getItem(int index) {
FragmentInfo info = fragments.get(index);
ImageViewFragment frag = (ImageViewFragment) Fragment.instantiate(
context, info.classz, /* null arguments*/ null);
frag.setImage(info.imageFile);
return frag;
}
#Override
public long getItemId(int position) {
return fragments.get(position).id;
}
#Override
public int getCount() {
return fragments.size();
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
public void add() {
FragmentInfo f = new FragmentInfo();
f.classz = ImageViewFragment.class.getName();
fragments.add(0, f);
notifyDataSetChanged();
}
}
Please change your code accordingly.
The problem is actually with notifyDataSetChanged. Just add to your Adapter:
public int getItemPosition(Object object) {
return POSITION_NONE;
}
However, I think you will get other problems when the Adapter actually tries to call getItem again. These problems will be in the lines of "Fragment Already Added".