Fragments reinstantiating and adding to activity by themselves - java

I have viewPager with adapter where I instantiate fragment and return it in getItem() method. So when Im on the first page I have only 2 fragments alive. When I rotate the phone, they both get destroyed and garbage collected (system calls their onDestroy() and onDetach() and I can see them in .hprof memory dump as ready to be garbage collected). However, when a new activity is created with new viewpager and 2 new fragments, for some reason, system creates 2 more fragments for those that were destroyed previously and attaches them to the activity, while not adding them to viewPager at all. They just sit in fragmentManager's mActive and mAdded arrays. When I rotate device few times, it creates these new instances each time. Now, this may seem like a leak that causes fragments not to be garbage collected but they indeed are. All these fragments have different #xxx number and are atached to a new activity within a new fragment manager. I've tried everything, any help or suggestions are much appreciated, thanks!

ViewPager handles the lifecycle of the Fragments it shows. As you mention it creates the visible Fragment and the ones next to it (if used with a FragmentStatePagerAdapter) to be able to smoothly swipe into them when the time comes. When the fragment is out of sight, it can be destoryed and recreated by the ViewPager at its will.
The default beheavior for a rotating screen is that the activity is recreated together with the ViewPager and the Fragments.
However this can be changed.
With android:configChanges="orientation" in the manifest you can prevent the activity of being recreated upon orientation change.
The other way of preserving the fragment instance upon an orientation change is to call setRetainInstance(true) in the fragment to be retained.

So I it was (unexpectedly:D) bad code. I had in my Activity's onRestoreInstanceState() piece of code that was creating and setting new adapter and so it put old fragments in background. Sorry for bothering with unanswerable question.

Related

When I rotate the screen, the fragment is destroyed and returned to Activity, which opened that Fragment. But why he's doing so?

I have an Activity which can open 2 different Fragments by 2 different Buttons. By the default that Activity when it creates, it is opening a Fragment, we call it "The Main Fragment".
The first Fragment to which we are going over by the first Button we meet zero problems with the Rotation, but the second one after the rotation disappears and the screen shows the Main Fragment's content. When I tried to rotate the screen back, I see the Main Fragment's content again. But why it is so, if I didn't write any code, which must return me to the Main Fragment without clicking a button.
What assumptions do you have?
Why this is happening ?
Default Behavior, Actiivty is getting recreated on orientation change so your fragment are.
Explanation
You need to understand Activity Life Cycle to understand why this is happening.
First, “rotating the screen” is not the actual scenario we are talking about today. Because any configuration change will cause Android to restart your Activity. A configuration change might be the device rotating (because now we have a different screen layout to draw upon), or it could be a language switch (because we need to re-write all those strings, which may need more room now OR it could be the scary RTL switch!), or even keyboard availability.
By reloading your app, what the system is actually doing is calling onDestroy() and then immediately calling onCreate(). This way, your Activity is as fresh as possible, with all of the right creation data (even though the user has been with you the entire time).
Now you have following option -
Either Fix Orientation for your app from AndroidManifest.xml
But oviously that is not a very good experience for user.
Save activityState with onSaveInstanceState()
This method will be called before onDestroy(). And, when your Activity is created, there’s a matching step onRestoreInstanceState(), which will also be called automatically. All of these automatic steps mean that you can let the system worry about saving and loading your data, because you planned ahead and mapped out what was important. (Or, you can skip onRestoreInstanceState() and load your saved state from the Bundle that comes with onCreate().
In you integrate Fragment in activity, because activity is getting destroy() so your fragment will also destroy() and will be recreated.
Please take a good read on Handling Configuration Change and this.
Once you understood the concepts things will start falling into your but it will only happen if you will complete your learning curve.
Happy Coding !
That is because onCreate is being called every time the screen is rotated. Probably you are displaying The Main Fragment from your onCreate method. You will face the same issue if you put your fragment display logic in onResume because just after onCreate, onResume is called.
Solution: store the fragment on top in shared preferences that way you know what to display every time onCreate is being called.

v4.app.Fragment when is it created and destroyed?

How exactly v4.app.Fragment works? I have viewPager with 7 Fragments. I was sure that when moving between fragments, depending on the situation each fragment can be automatically destroyed and created. However it seems not to be true.
I decided to play a bit with debugging and set some flag for my Fragment class object, something like
class MyClass extends Fragment {
public boolean myFlag=false;
When I set ex. true somewhere in the code which is run only once (ex. true is set after button click), it seems that this value is true until the app ends. Thus it suggest the object is kept all the time in memory.
However when user moves between Fragments onCreateView and onViewStateRestored methods seems to be called.
And now I feel quite confused. If Fragments are not destroyed, why those methods are executed by Android?
Do I have the guarantee that my Fragment object will be kept always with all fields (when user only moves beteween Fragments and doesn't leave the app)?
If not how should I save and restore its state? public void onSaveInstanceState(Bundle savedInstanceState) method seems to be only run when user left the app, not when user moves between Fragments.
Have you seen any good tutorial concerning ViewPager and Fragments?
And now I feel quite confused. If Fragments are not destroyed, why
those methods are executed by Android?
If you look at this diagram, Fragments do not need to be destroyed to call onCreateView().
Do I have the guarantee that my Fragment object will be kept always
with all fields (when user only moves beteween Fragments and doesn't
leave the app)?
This depends on what you are doing. If your case is dealing with ViewPager it really boils down to what PagerAdapter you use and your ViewPager configuration.
If not how should I save and restore its state? public void
onSaveInstanceState(Bundle savedInstanceState) method seems to be only
run when user left the app, not when user moves between Fragments.
It depends under what conditions you are wanting to restore state. For example, for orientation changes you can call setRetainInstance(true) on the Fragment and the Fragment's state will be preserved when there is a configuration change given your Fragment is not on the backstack.
Have you seen any good tutorial concerning ViewPager and Fragments?
The Android Guide has a good tutorial.
You can re-initialize all the values of a specific fragment in it's onCreate(...) method. So that when ever it is navigated to, it will have the default values that you setup in your onCreate(...) method.
Here are some useful links related to the Implementation of Fragments in a ViewPager:
1. http://thepseudocoder.wordpress.com/2011/10/13/android-tabs-viewpager-swipe-able-tabs-ftw/
2. http://androidtrainningcenter.blogspot.co.il/2012/10/viewpager-example-in-android.html
3. http://manishkpr.webheavens.com/android-viewpager-example/
4. http://thepseudocoder.wordpress.com/2011/10/05/android-page-swiping-using-viewpager/
I hope this helps.

Is it possible for an Activity to get Garbage Collected and not a child Fragment?

This call, which occurs in a Fragment, occasionally crashes due to a NullPointerException, especially when the app is not running in the foreground:
getActivity().getApplication());
This call occurs when feedback comes back from the server or when there's a need to redraw the fragment. I'm not sure why that call would throw a NPE, can the fragment remain in memory while the Activity gets GCed?
If it makes a difference, I'm using a SwipeyTab ViewPager to display different fragments.
Fragments can't exist without an attached Activity. If the activity is destroyed, then so will the fragment. Also note that getActivity() will return null until onAttach() is called on the fragment.
The issue was there was a long running thread on the Fragment, which returned results after the Fragment was deattached from the Activity. It seems strange for the Fragment to exist without being attached to an Activity (after it was already attached).

Fragment callbacks even though it is not part of UI

I am writing an app that uses Fragments for the UI, very similar to the Notepad sample code. It has a List of items then an editor for these items. In landscape mode the list and editor fragments are positioned side by side, but in portrait mode only the list is shown in the main activity, and the editor is shown by launching a new activity.
Within my editor fragment I have calls to findViewById to get at the individual components of the UI (mostly EditText fields). Under normal conditions this all works fine, but when the screen is rotated from landscape to portrait and the main activity is destroyed and created again it seems to call onActivityCreated (plus other callbacks) on my editor fragment even though it is not part of the display now (since in portrait mode it is just the list that is shown).
The problem is, findViewById to get the UI components returns null (I'm guessing because the fragment is not being displayed). But why are the calls being made at all? It is making me need null checks everywhere to make sure I don't try and use the UI components when they aren't on screen.
when the screen is rotated from landscape to portrait and the main activity is destroyed and created again it seems to call onActivityCreated (plus other callbacks) on my editor fragment even though it is not part of the display now (since in portrait mode it is just the list that is shown).
Correct. Android recreates all existing fragments during a configuration change. Or, if the fragment was added using a FragmentTransaction and you used setRetainInstance(true), the exact same fragment object is retained during a configuration change.
But why are the calls being made at all?
See above.
The problem is, findViewById to get the UI components returns null
You only need to call findViewById() in onCreateView(), and there you know whether the "UI components" exist, because you are creating them yourself.
It is making me need null checks everywhere to make sure I don't try and use the UI components when they aren't on screen.
Then use isVisible() or one of the other is...() methods on Fragment. Or, use setRetainInstance(true) so your fragment is not destroyed and recreated. Or, remove the Fragment (e.g., in onCreate() of the activity, if the passed-in Bundle is not null and you are now in portrait).

Avoid Android automatically re-add my fragment on orientation change

I have a ListFragment which depends on the hosting Activity to properly initialize. On first run, it loads up fine. Once I change the orientation, my app crashes. From the stack trace I can see it isn't me trying to add the Fragment prematurely, rather Android is trying to restore the Fragment.
I have setRetainInstance(false) set in the onStart method but can't find any method to disable the restoring of the Fragment once the orientation changes. Any ideas? Do I need to remove the Fragment prior to my app being destroyed?
Edit: I ended up delaying initializing the list until the Activity is ready. Android conveniently shows a 'loading' message until the adapter is set.
I ended up delaying initializing the list until the Activity is ready. Android conveniently shows a 'loading' message until the adapter is set.
I have a ListFragment which depends on the hosting Activity to properly initialize.
That may be your difficulty right there.
From the stack trace I can see it isn't me trying to add the Fragment prematurely, rather Android is trying to restore the Fragment.
Correct.
Any ideas?
I would focus on handling configuration changes properly. Between onSaveInstanceState() in the fragment and the combination of onRetainNonConfigurationInstance(), getLastNonConfigurationInstance() (both on Activity) and onAttach() (on your Fragment), you should be able to pass whatever stuff is in the old fragment to the new one without crashing. For configuration changes, do not rely upon "the hosting Activity to properly initialize".

Categories

Resources