My application has a ViewPager whose adapter returns three Fragments.
Each Fragment loads a list of data from Web in the onCreateView.
So let's call these fragments A, B, C.
Once the activity containing the viewPager is open, Fragments A and B are loaded.
But only A is visible now.
So if I swipe to the right, then B is visible and C is loaded behind the scene.
If I swipe to right again, then C is visible.
The problem is that, fragment A's onDestroyView() is called and all its loaded data is gone!
So if I come back to fragment A, then A's onCreateView() is called again and A's data is loaded from the web again.
Is it a default behaviour of ViewPager when using it with Fragment?
Is it possible to keek the fragment alive (by not calling onDestroyView()) even while it is not visible?
Thanks
try:
yourViewPager.setOffscreenPageLimit(2)
where 2 is the amount of pages to keep in memory on either side of the current page.
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 have a fragment that hosts a ViewPager with 3 fragments, 2 of them contain ListView (not inherits FragmentList)
The problem is:
If I click on one of the items in one of the list the application navigates me correctly to a new fragment, but, if I press the back button and go back to the ViewPager, a can see a blank fragment, only the first fragment who didn't have ListView is created, none of the other fragments are displayed, nor even their onStart is called
What's wrong? I suppose the fragment is not attached again, how can I solve this issue?
My situation: I have two ListFragments (call them A and B) managed by one Activity which keeps persistent references to both of these Fragments. When I click a button in Fragment A, I replace that with Fragment B. The problem starts when I do the following flow.
A -> B -> (scroll) -> (back button) -> B
In that case, when I go back to Fragment B the second time, the previous scroll position is maintained, which I don't want. Instead, I would like for Fragment B to start with its ListView at the top of its content.
Things I have tried which do nothing:
Calling setSelection(0) in onActivityCreated
Calling setSelectionAfterHeaderViews() in onActivityCreated
Calling smoothScrollToPosition(0) in onActivityCreated
Interestingly, all of these work if I post them on a Runnable. However, when I do that there is a weird flickering the second time I open Fragment B.
So, how do I get Fragment B to automatically scroll to the top each time it is attached to its parent Activity? I feel like there must be something blindingly obvious that I'm missing, but I'm really stumped right now.
You're calling the right methods, but you're calling them in the wrong place.
I assume you have code that switches between the fragments and you call it when an item is clicked in A. So whenever you do the switch set the scroll to the top, something along these lines:
protected void switchList() {
ListFragment a = (ListFragment) getFragmentManager().findFragmentByTag("a");
ListFragment b = (ListFragment) getFragmentManager().findFragmentByTag("b");
b.getListView().setSelectionAfterHeaderView();
getFragmentManager().beginTransaction().hide(a).show(b).addToBackStack(null).commit();
}
And one important note: never keep persistent references to fragments in your activities. Whenever you need a fragment get it from the FragmentManager. This is crucial since on configuration change (like a device rotation, or when your app is suspended and restored) the fragments are recreated, and the reference you kept leads to a 'dead' fragment. Not only is it a major leak, it will also prevent your code from functioning. any change you make to the saved fragment is not reflected on the screen because the screen holds the newly created fragment.
I have looked around and found variations of this question, but all of the answers seem to be ugly hacks. Is there no easy and proper way to achieve this?
Say for instance I have Activity A, which has a FrameLayout that can hold one fragment at a time. Lets say that when the Activity is first started it loads Fragment A into the FrameLayout, which consists of a ListView. When an item is selected in Fragment A it starts up Fragment B. The way I am currently doing this is by simply hiding Fragment A and then adding Fragment B since this preserves Fragment A's state. I am of course also adding this fragment transaction to the backstack.
So now Fragment A exists on the backstack. Say now I go back to my Android home screen and go to another app. While I am doing this, the Android system decides to destroy my application because the system needs more memory. When I navigate back to my application, how am I supposed to properly restore the state of Fragment B, and Fragment A which is currently on the backstack.
I cannot use setRetainInstance() since it does not work for Fragments placed on the backstack.
Essentially what I am trying to do is restore the backstack to exactly how it was before my application was forcefully closed. So Fragment A should be on the backstack (but not showing), and Fragment B should be currently showing. If I hit the back button, it should properly pop Fragment A off the backstack.
Some notes
Since the application was forcefully closed, it's savedInstanceState != null. Same thing holds for the fragments.
I'm having many crashing issues when programmatically adding 3 levels of nested fragments.
Currently, I have an Activity which loads Fragment A through its fragmentManager, which then loads Fragment B through A's childFragmentManager, which then loads Fragment C from B's childFragmentManager.
The fragments initially load up fine. But the problem is when the fragments are destroyed and then re-created. You'd think that when Fragment B gets destroyed, so will Fragment C. But it seems like Fragment C is left dangling.
As it is now, Fragment B gets loaded through a ViewPager in Fragment A. As I swipe from page to page, I occasionally get the following error:
java.lang.IllegalStateException: Fragement no longer exists for key android:target_state: index 1
If I remove fragment C from the equation, the error goes away.
It also doesn't crash if I load all fragments in their parent's fragmentManager (instead of childFragmentManager)
The answer is absolutely yes. You can have 3 levels. using it successfully in my App.