In my application I am using ViewPager from the support library- v4
In main screen I have viewPager which got max 5 Fragment, all fragment belongs to one class ArticlePager
Now in main screen there are list on categories, now the content of the pager is based on that selection,
The problem I am having is, I have used FragmentPagerAdapterwhich stores the Fragment and if the fragment is already exist, It will return the old Fragment without recreating it. That things runs perfectly, but Problem Occurs # the time of orientation change.
For instance
If there are 5 View normally in every fragment For the given position, but There are also some which contains 2-3 views. Now if I change the orientation on page No. lets say 5 which contains only 3 view inside.
So, by now in every category on Page 5 I'll got the view containing 3 view, which is not something I want.
In my application each category contains the pagination
Is there any way such that i can destroy and recreate the Fragment on click of category? or any other work around
Thank you
OK thanks to open source I find my solution, FragmentPagerAdapter I have override the method instantiateItem and got the solution.
This can be easily achieved by FragmentStatePagerAdapter such that it doesn't store the fragment. It recreate it all the time, but I don't want that in 100's of page because of only few pages.
So if I understand correctly, your problem is that after rotation, the wrong set of fragments are in you ViewPager?
Why don't you check the current selected tab in onResume() or onStart() of your Activity, and create/assign a new PagerAdapter for you ViewPager with the correct fragments?
Related
I am trying to create an app using Viewpager2 that allows scrolling between fragments similar to below image but WITHOUT the tablayout at the top.
So if you scroll left and right you would swtich between the fragments. Thats fine and dandy.
However my final app would have more than 5 tabs so i dont want the tab layout listed on top. Instead I would have a menu option that would let user choose which fragment to view.
I cannot figure out how to get the viewpager to go to a specific fragment directly (eg. from 2nd fragment to the 5th fragment), and when navigating between fragments I do not want a fragment to start from scratch if if was created already.
I am using FragmentStateAdapter with my ViewPager2. Should i be using another adapter for this? Any ideas woule be greatful.
The easiest way to implement this feature is to define your ViewPager as static in your activity (so you can access it from anywhere in your application, including fragments). You can make it public, or you can make it private and create a getter for it.
private static ViewPager mViewPager; // This is the global variable
public static ViewPager getViewPager() { return mViewpager; } // This is the getter
Now lets say we have an activity MainActivity which contains the ViewPager. Each fragment inside this ViewPager contains a button which should control the page (doesn't have to be in the ViewPager, could be anywhere as long as it has a reference to your Activity and that Activity is still running, so don't start another one).
ViewPager contains the method
setCurrentItem(int item, boolean smoothScroll)
(smoothScroll is optional and is just for animation purposes)
Now you can do:
MainActivity.getViewPager().setCurrentItem(itemNr);
Or if you want a fancy scroll animation:
MainActivity.getViewPager().setCurrentItem(itemNr, true);
Now your second question / issue was that you mentioned you don't want fragments to get recreated. In that case I think it is better to use FragmentPagerAdapter, which maintains your fragments. You can call the following method to set a limit to these pages:
mViewPager.setOffscreenPageLimit(LauncherViewPageAdapter.NUMBER_OF_PAGES); //NUMBER_OF_PAGES was just a static constant in my LauncherViewPageAdapter class which extended ViewPageAdapter.
Note: Default this limit is 3, but you really don't have to worry about performance. I implemented 4 pages / fragments (widgets, tiles, app list, application settings) without any memory issues (even on older devices). Just don't put them full with bitmaps / heavy memory usage stuff.
I'm currently working on a launcher application which also uses ViewPager, so feel free to reply with a question about the ViewPager, since I solved the basic issues I had.
You can make use of setCurrentItem method of your ViewPager2. Just pass the index your wish to navigate to starting from 0. As for not wanting the fragments to start from scratch simply use setOffscreenPageLimit method of viewpager2 and set it to like 4 in case you have 5 pages so that all 5 pages stay in memory. It actually defeats the purpose of FragmentStateAdapter and ViewPager2 though.
I have an Activity with ViewPager and three Fragments with-in. One Fragment contains ListView with custom CursorAdapter which loads data from database.
I've noticed that my cursor adapter loads data every time I switch Fragments in ViewPager. I think that it's normal and is due to the fact that every Fragment has its own lifecycle.
Regarding this it will be great pleasure for me if the users of the stackoverflow explain about their experience or best practices at all.
Thanks!
ViewPagers maintain the state of only certain number of fragments, which defaults to 1 for both sides of the current selected fragment. For example, if you have 3 fragments, when the first is selected, only first two fragments will be instantiated and have the listview data loaded. Alternatively, if you have the second fragment selected, the first and the third will be instantiated. If you switch to the third fragment, the second fragment will be retained, but the first one will be lost. However, you can set the number of fragments to be retained with calling setOffscreenPageLimit method on viewPager with any number of fragments to retain you need. Though you should remember, that setting the number too high may cause your app to consume too much memory.
For example, if you want your fragment to not reload listview content from db while switching fragments and you have 3 framents in your viewPager, you may write the following code:
ViewPager mViewPager;
mViewPager.setOffscreenPageLimit(2);
I'm experiencing a really weird behavior and I suppose I'm missing something.
I have an activity that has a Fragment inside. This Fragment has a ViewPager which obviously hosts other Fragments.
To populate that ViewPager I need info from four tables. Once the first loader finishes loading (let's call it 0), I init the other loaders.
The user swipes through the pages and when he/she reaches the last page, the Fragment that is loaded on that last page inits loader 0 again, which takes a huge amount of time to reach onLoaderFinished. If I load that "last page fragment" without being inside the ViewPager, it loads instantly, as expected.
Is there a way to deal with this situation of a Fragment inside a ViewPager using the same Loader that was used to populate the ViewPager itself?
Thanks in advance.
Try calling setOffscreenPageLimit() in onCreate() (after initializing ViewPager). The OffscreenPageLimit sets the number of pages that should be retained to either side of the current page. With this all of your fragments will instantiate. Though you must not do so if there are large number of pages.
I solved the problem by not calling the Loader inside the Fragment and passing the array of data I wanted from the database in a Bundle as a Serializable.
I have implemented an activity that displays fragments in a viewpager. The activity initially displays 5 fragments of a given type (type A). Each type A fragment contains a list of information. When a button is pressed, the fragments are replaced with another tpye of fragments, type B (i.e., fragments that use a different layout and display different information are loaded).
I have implemented this with a ViewPager and a custom FragmentStatePagerAdapter. The custom FragmentStatePagerAdapter overrides the getCount, instantiateItem, getItem, getItemPosition, etc. functions and all works fine. When I press the button the views switch from fragment type A to fragment type B. In order to do this I am using a replace fragment transaction and I also call notifyDataSetChanged on the adapter. The switch from type A to type B fragments is accomplished by checking which type of fragment I need to create in the adapter's getItem function. The problem is that the switching process (i.e., changing from fragment type A to fragment type B and vice versa) takes some time (around 2 seconds) - this delay is quite noticeable and annoying.
This occurs because the adapter's getItemPosition function returns POSITION_NONE. When POSITION_NONE is returned, the viewPager recreates the fragment. Furthermore, when the replace transaction is executed, all items of the adapter are removed and all new ones are recreated. The same happens when I switch back to fragments type A.
Does anyone know if there is a better or faster way to do this? Using a FragmentPagerAdapter should not be a good solution since the number of fragments in the viewPager could grow.
I have commented out the updating of the fragments and the problem is gone so the problem is the time it takes to update the fragments. Is there a way to update the fragments asynchronously? That should take care of the problem.
The ViewPager instatiates by default a minimun count of Fragments. In general the left and right one of the current Fragment. So you don't need to care about the total number of Fragments.
You can control the total number with the ViewPager.setOffScreenPageLimit() method.
Also a AsyncTask seems to be a good idea to manage the intensiv work of your Fragments.
I'd like to cache a fragment view. My Activity has swipeable tabs and each tab calls a different fragment. But when i swipe between tabs the transition seems a quite slow because of the destruction of the fragment view, that is rebuilded during the swipe operation. Does anyone know how can i cache the view of each fragment to prevent this issue?
I work with library support v4 and api 14
I tried to implement a constructor for the fragments, called by the activity container of the fragments: i call the constructor, the fragments are created as variable of the activity class and then, whenever a fragment has to show itself, the activity class returns the fragment object i created before, but this doesn't improve my application a lot because the view of the fragment is destroyed anyway
This is because internally by default the pager loads a maximum of 3 pages (fragments) at the time:
the one displaying, previous and next so if you have 5 fragments this will happen while you move from first to last: (where x is a loaded fragment)
xx000
->
xxx00
->
0xxx0
->
00xxx
->
000xx
Try using
myPager.setOffscreenPageLimit(ITEMS_COUNT-1);
This will tell the pager to keep all of them in memory and not destroy/create with every swipe (keep a close look on the memory management)