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".
Related
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.
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.
There are a bunch of other questions about this topic, but I have not been able to figure this issue out.
In the Android documentation (http://developer.android.com/training/basics/activity-lifecycle/recreating.html) it says:
By default, the system uses the Bundle instance state to save information about each View object in your activity layout (such as the text value entered into an EditText object). So, if your activity instance is destroyed and recreated, the state of the layout is restored to its previous state with no code required by you.
So I tested this in the emulator by simply creating a view that contains a EditText-view. I then enter information into it and press the home button. When I reopen the app, the information is gone. Shouldnt this be persisted automatically or am I missing something?
Well you are partially wrong and partially right. You are wrong, because the quotation in grey is taken out of the context. I'll explain briefly, by making the correct quotations from the link you provided:
When your activity is destroyed because the user presses Back or the
activity finishes itself, the system's concept of that Activity
instance is gone forever because the behavior indicates the activity
is no longer needed. However, if the system destroys the activity due
to system constraints (rather than normal app behavior), then although
the actual Activity instance is gone, the system remembers that it
existed such that if the user navigates back to it, the system creates
a new instance of the activity using a set of saved data that
describes the state of the activity when it was destroyed.
Now, after that paragraph we have a clarification:
Caution: Your activity will be destroyed and recreated each time the
user rotates the screen. When the screen changes orientation, the
system destroys and recreates the foreground activity because the
screen configuration has changed and your activity might need to load
alternative resources (such as the layout).
Another one, several linew below is:
To save additional data about the activity state, you must override
the onSaveInstanceState() callback method. The system calls this
method when the user is leaving your activity and passes it the Bundle
object that will be saved in the event that your activity is destroyed
unexpectedly. If the system must recreate the activity instance later,
it passes the same Bundle object to both the onRestoreInstanceState()
and onCreate() methods.
This Bundle (Bundle savedInstanceState) is used, when the application accidentally crashes OR if the rotation of the screen is enabled (to name few), which is also destoying (then recreating) your foreground.
You can also take a look at the following section "Save Your Activity State", but I would recommend you this link here.
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).
I am writing an app where I get all the data from the rest call and display all the data in a custom component list(based on Linear Layout) which is added to a LinearLayout. I write this code in onCreate of the activity.
The problem is when I switch activity using startActivity, and come back to the calling activity (using startActivity) then onCreate is called again. I see onPause, onStop called when I call other activity.
Is there any way that I can save the application's state?
Check this question: "How do I save an android application state".
Edit:
You can also avoid some calls to onCreate() by adding a
android:launchMode="singleTask"
to your Activity in the AndroidManifest.