I'm using a ViewPager in my app. There are three fragments inside the PageAdapter that is set in the ViewPager. All works perfectly fine and I can switch between all three fragments. I have 3 buttons that allow me to switch between adapters 1 to 3. The problem is noticed when I click buttons 1 and 3 at the same time. Here's what happens:
Fragment 1 - Fragment 3
onAttach
onViewCreated
onResume
onPause
onAttach
onViewCreated
onResume
onPause
As you can see from above, the second fragment is never paused and therefore never resumed. Both fragments modify the same recycler view onResume so with the behaviour above I end up with the incorrect state of my recycler view.
Any thoughts on why this might be happening and how I can fix this?
A ViewPager loads (by default) the current page, the previous page and the next page, since you have only 3 pages the second fragment is always resumed.
the solution is to set up a OnPageChangeListener and modify the recycler view in onPageSelected instead in onResume
Related
So I have a fragment inside a viewpager which is contained inside a fragment which is getting initialize'd as shown in the debugger but doesn't have it's onCreate,onCreateView or any such methods being called. The activity containing has a bottom navigation view and contains 4 such fragments and this issue is only happening in 1 such fragment.
All these fragments and viewpagers and fragments inside them are created on the oncreate of the activity. If I move the logic to create the fragment to when a bottom tab is clicked, this issue gets solved on.
How is this possible ?
Only the currently active fragment and the two directly adjecant fragments are created when the viewpager is first shown. so the fragment for the first page, the fragment for the page shown if you "scroll to the left" and the fragment for the page shown when you "scroll to the right". the 4th fragment will be created when it is put in the next adjecant position.
so if you have fragments a,b,c,d in a viewpager like -a-[b]-c-d- where b is the first visible page, only a,b and c will be created at startup. when you scroll to c -a-b-[c]-d- onCreate for fragment d will be called.
You can control number of pages/fragments preloaded when you launch your activity by setting it's off Screen Page Limit on your view pager adapter. like this
mViewPager.setOffScreenPageLimit(limit)
If you set limit to 0 than only first fragment would be load.
https://spotandroid.com/2016/11/23/android-tricks-viewpager-and-offscreen-tabs/
https://techcodegeek.wordpress.com/2015/06/23/android-viewpager-and-performance-improvements/
Need more detail to know your issue.Issue which you are facing is not understood with information you have provided.
I am using a ViewPager inside a TabLayout. The ViewPager has 3 pages where each page is a fragment.
When the activity containing the TabLayout starts, the fragment callback methods upto onResume() are called for fragment1, which is as expected and fragment1 is displayed on the screen.
However, logcat shows that the callback methods upto onResume are also called for fragment2, although fragment2 is currently not being displayed on the screen. This looks odd to me since onResume should only be called when a fragment is about to become visible.
When I select fragment2, onResume is called for fragment3, although fragment3 is not being displayed. So there seems to be a pattern to this behaviour.
What could be the cause for this?
Update: The ViewPager I am using is a subclass of FragmentPagerAdapter.
If is default behavior of ViewPager to call next Fragment when ViewPager is initilized.
You need to use setOffscreenPageLimit()
setOffscreenPageLimit() sets the number of pages that should be retained to either side of the current page
Default value is 1 so next Fragment to the left and to the right will stay in memory.
To prevent from calling next Fragment you need to set 0 value to OffscreenPageLimit
viewPager.setOffscreenPageLimit(0);
on the ViewPager object.
EDIT:
But i have checked by setting limit to 0.
setOffscreenPageLimit(0) will not work now. when you set limit to 0 you can see below warning in LogCat:
Requested offscreen page limit 0 too small; defaulting to 1
So i advise you to either call setOffscreenPageLimit(2) which will keep all your 3 Fragments in memory otherwise don't call setOffscreenPageLimit(int limit) on ViewPager.
Two things contribute to this behavior:
Fragments are not required to have a UI, in which case it is never "visible" on screen. Basically, if a Fragment is attached to an Activity, its lifecycle methods will be called as appropriate.
ViewPager loads items to either side of the item that is currently displayed. This is in order to have content to show as the user scrolls the page with his finger. By default the off screen page limit is 1, which means that when your first fragment is the current item, the second fragment is loaded off screen in preparation for scrolling.
You can always check which item is displayed by the ViewPager using getCurrentItem(). If you are having problems because the fragment are destroyed and recreated needlessly when they go beyond the off screen page limit, you can increase the page limit with setOffscreenPageLimit().
I have a action bar with 3 navigation tabs: Fragment 1, Fragment 2 and Fragment 3. Now, I want to do a task whenever Fragment 3 selected, so I put my task code in onCreateView() method. However, I find that Fragment 3 does not do the task, it means the onCreateView() method is not called. (I check this by logging). The other strange things is:
- When I slide: F2-> F3: the task not work.
- When I slide: F1->F2->F3: the task work. (onCreateView() method called)
I don't know why F3's onCreateView() method called when I slide from F1 to F3?
Any ideas for this?
The remark from tyczj is correct but it does not give a solution to the problem.
In your F3, just override setUserVisibleHint(boolean) and when boolean is true, it means that F3 is now visible inside the ViewPager.
Note that you can rely on this method because you are using a ViewPager and it properly set the user visible hint when a fragment is shown.
When you are not using ViewPager, you can't rely on this method unless you are explicitly calling the method when you know that the fragment is visible.
EDIT : setUserVisibleHint() is not called by the ViewPager, but by the FragmentPagerAdapter.
Because a ViewPager loads the next view so that it is ready when you want to scroll to the next fragment. by default the viewpager loads the previous current and next fragment in the ViewPager so when you scroll from F1 to F2, F3 is going to be loaded in so that you have a smooth scroll when you go to F3
The previous answer tells you why what you are doing won't work. But to correct it you will want to create a AsyncTaskLoader and use the fragments LoaderManager to load and manage the task. See http://developer.android.com/guide/components/loaders.html
Scenario:
I using a ViewPager inside a Fragment. This ViewPager inflates 3 fragments (AFragment, BFragment, CFragment) pages using FragmentPagerAdapter.
I have printed logs inside
onCreateOptionsMenu
onPrepareOptionsMenu
of all 3 fragments.
Problem:
For AFragment when created onCreateOptionsMenu was called only once,
but when I swiped to BFragment onCreateOptionsMenu and
onPrepareOptionsMenu for BFragment were called twice. And similar
thing happened with CFragment.
Can anyone explain why this is happening and How I can avoid it?
Thanks.
Because android by defaults loads a next and previous fragment in background, in order to load fragments efficiently and to remove lag.
However you can customise the same by using setOffscreenPageLimit (int limit), Which is used to set the number of extra fragments you would like to load in background. By default its set to 1.
Read Android fragments strange load for more information
I'm new in using view pager, I've done everything correctly, I conveted my activities into fragments and put them in FragmentPagerStateAdapter.
When testing it in the emulator, what I noticed is that the onCtreate to the onResume are called one fragment before the actual visibility on the view pager - it makes sense, the device wants to get ready for the next step, but the problem is that I have one fragment which calls a dialog every onStart so that actually happens on the wrong fragment.
What should be done?
You can use an OnPageChangeListener on your ViewPager to detect when you navigate to the right fragment.