I have tried using an extended FragmentStatePagerAdapter and an extended FragmentPagerAdapter to achieve what I'm trying and neither seem to work. I am sending down a JSON object from my server to fill an object model on the android client. On first load, everything works perfectly, I can swipe through pages just fine from beginning to end. Here is my object model:
ContestEntriesModel.java
public class ContestEntriesModel {
public int ContestId;
public String ContestName;
public ContestEntryModel[] entries;
}
As you can see, there is an array of ContestEntryModel. Each of those models looks like this:
ContestEntryModel.java
public class ContestEntryModel {
public long ContestEntryId;
public int UserId;
public String FullName;
public int Comments;
public string ImageUrl;
}
As stated above, when the first data payload comes down from the server, I am filling one fragment per item in the ContestEntryModel[] array with data from that model (including an image from an internet resource (ImageUrl)), and that works perfectly. I can swipe until my fingers bleed and all is good in the world.
I'm trying to now send another payload down from the server which has the items in the array in a different order (I will ultimately add new items too, but one step at a time). I have searched high and low on StackOverflow for a solution to this and posted a question yesterday which got me close to where I need to be (thanks Reinier), but I'm still struggling with getting all of my fragments to reorder and have the adapter completely refresh with the new order. The adapter seems to cache a few of the slides (the ones adjacent to the one I'm currently viewing) and they don't "refresh" until I've slid a few images past them and then return. Yesterday's trouble was getting the currently viewed slide to not "refresh" when the new data comes down from the server which I have working...sort of. Let's say I have 7 items in my array and I swipe to slide #3 (index 2) on the first load. I then push new data from the server which is just ordering the array in reverse. The currently viewed slide (slide #3) should then move to index position 4 and I should only be able to swipe to the right 2 times (index position 5 and 6). Instead what is happening is that it's remembering the current index position for that slide (index 2) and keeping it there. As I said above, slide #2 (index 1) and slide #4 (index 3) are also being maintained. My expected behavior is that those slides should reverse positions around slide #3 (index 2).
Here is my implementation of my PagerAdapter (this is the version that is a FragmentStatePagerAdapter not a FragmentPagerAdapter:
ScreenSlidePagerAdapter:
public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public ContestEntriesModel entries;
public ScreenSlidePagerAdapter(FragmentManager fm, ContestEntriesModel Entries) {
super(fm);
this.entries = Entries;
}
public long getItemId(int position) {
return entries.entries[position].ContestEntryId;
}
@Override
public int getItemPosition(Object object) {
android.support.v4.app.Fragment f = (android.support.v4.app.Fragment)object;
for(int i = 0; i < getCount(); i++){
android.support.v4.app.Fragment fragment = getItem(i);
if(f.equals(fragment)){
//Log.d("currentPosition",Integer.toString(i));
return i;
}
}
return POSITION_NONE;
}
@Override
public android.support.v4.app.Fragment getItem(int position) {
long entryId = getItemId(position);
//Log.d("EntryIds",Integer.toString(entryId));
if(mItems.get(entryId) != null) {
return mItems.get(entryId);
}
Fragment f = ScreenSlidePageFragment.create(position);
mItems.put(entryId, f);
return f;
}
@Override
public int getCount() {
return NUM_PAGES;
}
}
currently I'm setting a static property on my activity for the adapter (I use it in a few other "external" classes) like so:
MainActivity:
public class MainActivity extends FragmentActivity {
public static int NUM_PAGES = 0;
public static ViewPager mPager;
public static PagerAdapter mPagerAdapter;
public static ContestEntriesModel Entries;
public static HashMap<Long, android.support.v4.app.Fragment> mItems = new HashMap<Long, android.support.v4.app.Fragment>();
public static Long CurrentEntryId;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.entries_layout);
GetEntriesTask task = new GetEntriesTask(43);
task.execute();
}
public void LoadEntries()
{
mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager(), Entries);
mPager.setAdapter(mPagerAdapter);
mPager.setPageTransformer(true, new MyPageTransformer());
mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
ContestEntries.CurrentEntryId = ContestEntries.Entries.entries[position].ContestEntryId;
Log.d("currentEntry",Long.toString(ContestEntries.CurrentEntryId));
invalidateOptionsMenu();
}
});
}
//the rest is omitted as it's not pertinent to my issue.
When a new dataload comes down from the sever, I am just setting my static property (Entries) to the new version. I also tried accessing the public property in the PagerAdapter (entries) to modify that directly, but that is not accessible for some reason (even though the class and the property both have a public accessor). I assume that is where this is going wrong because it's that instance that I need to be modifying, but honestly, my brain is fried at this point and I'm just not sure. Here is the code I'm using for the update:
UpdateCode:
@Override
protected void onPostExecute(ContestEntriesModel entries) {
Fragment currentFragment = MainActivity.mItems.get(MainActivity.CurrentEntryId);
Log.d("fromUpdate",Long.toString(MainActivity.CurrentEntryId));
MainActivity.Entries = entries;
MainActivity.NUM_PAGES = MainActivity.Entries.entries.length;
//MainActivity.mItems.clear();
MainActivity.mPagerAdapter.notifyDataSetChanged();
MainActivity.mPager.setCurrentItem(MainActivity.mPagerAdapter.getItemPosition(currentFragment));
}
So using that, it does keep me on the current slide (which is what I need), but that slide is not repositioned correctly as mentioned above, nor are the other adjacent slides "refreshed". Again, assuming I'm on slide #3, if i swipe to the left once the old slide #2 is still there. If I swipe to the left twice, slide #1 is updated to the "new" slide (slide #7 from the first load). If I then swipe back to the right once, slide #2 is still there (should be slide #6). If I then swipe to the right once more, the "original" slide that I was on that I need maintained, is now replaced with slide #5 (again that number is from the original load). If I keep swiping to the right all the way to the "new" slide #5, I see the original again. That is where it needs to be on the new data load, in that position.
I sincerely apologize for this wall of text, but I thought if I could provide as much code as possible, this would make more sense. I've read several different approaches to this problem but I can't wrap my head around any that suit my needs specifically.
Any suggestions / code help would be greatly appreciated.