Change order of ViewPager and update views - android

I have a ViewPager with 10+ views. I wish to change the order of the pages occasionally i.e.
Page 1 | Page 2 | page 3
to
Page 3 | Page 1 | Page 2
For the tabs I am using ViewPagerIndicator, I am able to update the order of these by changing the order of my adapter and calling:
mViewPagerIndicator.notifyDataSetChanged();
However, what I cannot update is the content of the ViewPager, for example if I update the ViewPager adapter (to the new order I wish the pages to be in) and call:
mViewPager.getAdapter().notifyDataSetChanged()
This has no effect. The tab indicator bar is updated fine but the content of the page still shows the old order.
Is there a way to change the order of pages in a ViewPager adapter and get the ViewPager to reload all it's views?
My ViewPager adapter extends FragmentStatePagerAdapter and my overridden methods are as follows:
#Override
public Fragment getItem(int position) {
return MyCustomFragment.newInstance();
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
//super.destroyItem(container, position, object); // Commented out to ensure views are not destroyed
}
Thanks

It's tricky to do with FragmentStatePagerAdapter because you'll have to implement the logic yourself, but it's a lot easier with FragmentPagerAdapter which already provides the functionality for this purpose.
Calling .notifyDataSetChanged() invokes the getItemPosition(Object object)-method of your adapter. This is where you should provide ViewPager with the information of where to put the Fragment passed in the parameter object, by returning the page-number you want the Fragment to be positioned on.
For an example on how to do this, check out my answer here.

If performance isn't super important, it's really easy to force the FragmentStatePagerAdapter or FragmentPagerAdapter to redraw (invalidate) all of its views/fragments: just override getItemPosition and call notifyDataSetChanged() as you normally would.
#Override
public int getItemPosition(Object object) {
return POSITION_NONE; //In source code, POSITION_NONE = -2 FYI
}
For more info, check out my post: How to use orderByKey() in descending order instead of ascending #Askfirebase

Related

reuse fragments in FragmentStatePagerAdapter

MY PROBLEM
I am creating an Android app where the user swipes through a load of cards (like tinder)
Each card is VERY UI heavy (has a google map view and an admob ad)
I tried loading the list into a fragment adapter. This means a fragment for every single item. This is very memory intensive as I am creating about 30 google map views and 30 admob views for the 30 items.
My nexus 5 unsurprisingly crashes under this unnecessary heavy load.
My attempted solution
I have created 3 instances of the fragment.Loaded these fragments into a HashMap.
//for currently displayed fragment
key = 0
//for previous page
key = -1
for next page
key = 1
I keep the previous index.
On the getItem method of the adapter I detect if the user has gone to the previous page or the next page.
I get the associated fragment and return it.
My problem is I keep receiving exceptions like:
IllegalStateException: Fragment already added
I have tried detaching and/or removing the fragment but no luck :(
Any suggestions?
Thanks
From the Google Play ViewPager example...
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return new ScreenSlidePageFragment();
}
#Override
public int getCount() {
return NUM_PAGES;
}
}
In the getItem(int position) you have to create a new Fragment instance, old fragments should be destroyed when the setOffscreenLimit has been reached. I get the feeling originally you were creating all 30 Fragments at once?
take a look at android's effective navigation sample for proper use of fragmentstatepageradapter.
http://developer.android.com/shareables/training/EffectiveNavigation.zip
I recommend put your admob in the main activity below viewpager. so u dont need to restart it everytime. and google map inside swipe view is not recommended by google as it is hard to handle both swipe and map zoom features. So simply use static map api it provides a screenshot of map according to the coordinates u provide and implement an onclick method to launch map as another activity.

How to restart the fragment in viewPager

I want to restart the fragment, i.e. recall the onCreate and onCreateView method of fragment when refresh button ia clicked. How to achieve it?
The answer probably lies in the getItemPosition() method of your ViewPager adapter. To quote from the Android Developers blog:
If you’re trying to replace Views in your ViewPager, it isn’t enough
just to change the data set behind the adapter and call
notifyDataSetChanged(). You also need to ensure that you’ve correctly
implemented getItemPosition(Object object) and return POSITION_NONE
for items that have changed and return POSITION_UNCHANGED or the
actual position for items that haven’t changed.
If you call notifyDataSetChanged() on your adapter, and your getItemPosition() is set to:
#Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
Then every fragment will be re-created from scratch.

Deleting page from FragmentStatePagerAdapter causes issues

Our application has multiple fragments to show data specific to location. We have used FragmentStatePagerAdapter and ViewPager. User should be able to add new page and delete as well. While adding new page works fine, deleting the existing page shows issues. When I verified I had 3 pages. I deleted the 2nd one from left navigation menu button.When I try to slide to the 3rd page, it shows the view of delted page that is 2nd page. ANd it does not show the 3rd page.
I have Overriden getItem() where I return the new page. I have adjusted the ItemCount when I added/deleted the new page to Adapter. And I called startUpdate() before I add/delete, destroy() to delete any fragment object in a position, finishUpdate() after everything done. And finally notifyDataSetChanged().
Looks like nothing is missed but something. I still see the view of deleted fragment and next to it is blank page or something similar depending on which position's page I delete.
I see Removing fragments from FragmentStatePagerAdapter is something similar but could not help my case. Help me with any clue.
I could solve it. Though the answer by Wize here Replace Fragment inside a ViewPager does not solve my issue, I could find a hint from this. I had to override getItemPosition(Object object) which tells system that particulat 'object' is not-changed/no-more-exist.
I have the list of fragments (references) locally as well which I modify according to the list that FragmentStateAdapter maintians and here is my code for getItemPosition():
#Override
public int getItemPosition(Object object) {
if (object instanceof myFragment) {
if (!mFragments.contains(object)) {
return POSITION_NONE;
} else {
return mFragments.indexOf(object);
}
}
return super.getItemPosition(object);
}
Also, I only called notifyDataSetChanged() after I add/delete fragments. I removed startUpdate(), finishUpdate() all that.I do not knwo where exactly where they are used. But it worked without them.

Updating ListView inside Fragment (ViewPager)

i've a simple chat application with ViewPager for Active Chats, now, i use
#Override
public int getItemPosition(Object object)
{
return POSITION_NONE;
}
but this causes the all fragments to be recreated, and if there is too many messages it will lag, and also it closes keyboard whenever a message is received, so i attempted to override instantiateItem, but i couldn't get to anywhere, since i didn't know what to do with it, i wanted to update all listviews/fragments, not just the active one.
i also tried to use the onCreateView of fragments, get the listview, add an adapter to it, and add that adapter to a Array list, and whenever each messages comes, all adapters in this array list are updated, but this didn't work as expected, i had to move away from ViewPager then back to it again (Since the ViewPager is inside a tabHost) for messages to be displayed.
any help is appreciated, thanks.
Please use setTag() method in getItemPostion() for the views to update them rather then returning POSITION_NONE. The reason of using setTag() and the way how to do that is well explained in this post ViewPager PagerAdapter not updating the View

ViewPager + FragmentStatePagerAdapter : need to know when fragment is displayed (selected)

I am using a ViewPager plugged to a FragmentStatePagerAdapter. Each fragment contains a listview. In this listview I wish to display ads and make calls to a analytics server. I only want to make those calls when the user navigates to a fragment (so I cannot use the onCreateView or onActivityCreated events in the Fragment). Is there an event I can hook on to this end ?
Update
I realized that the way I am fetching my current fragment is flawe
#Override
public void onPageSelected(int page) {
this.currentPage = page;
tabsAdapter.getItem(page);
}
getItem(int position) in the pager is actually responsible for instanciating the fragments, so it would create a new unattached fragment (hence getActivity() returning null). I think I will us an approach where I keep a map of the fragments (<Position, Fragment>), i will remove the fragment from the map when destoryItem is called in the pagerAdapter.
You are right, best option is the second solution here:
http://tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part-ii.html
so your thoughts are correct.
How about this:
http://developer.android.com/reference/android/support/v4/view/ViewPager.OnPageChangeListener.html
The onPageSelected(int) method sounds like it does what you want.

Categories

Resources