I realized that there are lots of question on this topic already asked on SO.
But I don't even know the basic when it comes to saving the state of an activity.
(Refer Screenshot Below) When app launches,
1) ScrollView item 1,2,3,4 are visible
2) table containd data which is populated due to Gainer button.
As showed in below screenshots, While app is running in PORTRAIT mode, I
1)scrolled down to ScrollView item 4,5,6
2)pressed the Loser button so accordingly data in the table below the button changes.
3)I'll even change content of graph dynamically(which I had not done yet).
Now I switch to LANDSCAPE Mode so
1)ScrollView is showing ScrollView item 1,2,3,4
2)table is showing data which is populated due to pressing Gainer button.
3)graph is as it is as I've not changed it yet(which I will change later).
So what happens is when I change the orientation, my activity is getting re-launched. So if user is performing some task in one orientation and he changes the orientation, then whole progress will be lost.
I know I need to save the state of the activity and Restore it when orientation changes.
But I don't know from where to start and what to save.
ANY HELP WILL BE LIFE-SAVER !
Option #1: Override onSaveInstanceState() of your Activity and put whatever information you want in the supplied Bundle. Your new activity instance will receive that Bundle in onRestoreInstanceState() (or onCreate()). Here is a sample project demonstrating this.
Option #2: Override onRetainNonConfigurationInstance() of your Activity and return some object that represents your state. Your new activity instance can call getLastNonConfigurationInstance() to retrieve that object, so the new activity can apply that information. Be careful, though, not to have the old activity return something in the object that holds a reference back to the old activity (e.g., a widget, an instance of a regular inner class). Here is a sample project demonstrating this.
Option #3: Convert this activity to a fragment. Have the fragment call setRetainInstance(true); on itself during its initial setup. Add the fragment dynamically to some activity via a FragmentTransaction. Now, when the configuration changes, the fragment is retained, so all your widgets and state are retained. Here is an overly-complex sample application demonstrating this.
Those are the three recommended approaches nowadays.
Related
I have a main activity which takes me to another activity using startActivityForResult() . The resulting activity performs a process and ultimately returns an object back to main activity . My question is:
If user presses home button on his android screen while he was in result activity and android cleans up the resources of my app, Do i have to only save the state of my resulting activity of or i do also have to save states of both the main and resulting activity in order to restore my app current state.
If i have to save the states of both the activities, how do i do that ?
P.s:
I have some data added to my main activity. I would like to restore my state for both result and main activity .
If user presses home button on his android screen while he was in result activity and android cleans up the resources of my app, Do i have to only save the state of my resulting activity of or i do also have to save states of both the main and resulting activity in order to restore my app current state
You do not need to trigger onSaveInstanceState() manually. So everything with a state which is saved by executing this method will be persisted automatically.
BUT
not even the state of all Views will be saved by default. For example a TextView of which you changed the text will revert to the text in the layout file if you do not set the attribute android:freezesText="true"
if you have some data stored in a field (property) of your Activity, it will be lost if you don't take steps to persist it (note this is also valid for ViewModels - they survive a configuration change but they are not immortal).
Options for persisting data: if related to the View layer like e.g. a selected item in a RecyclerView, one can override onSaveInstanceState() and save the item id in the savedInstanceState Bundle. Other possibilities include writing to SharedPreferences and having a SQLite database. See also Options for preserving UI state and Data and file storage overview
I have a single ActionbarActivity with two fragments. I have a menu option (maintained in MainActivity) to open a camera intent and capture a picture. When I return from this event, I want to update the first fragment.
Currently, if I select this menu option while the first fragment is visible, I can update the UI by using a reference to an instance in the MainActivty's onActivityResult(). However, if the second fragment is currently visible, the app crashes. (I am away from Android Studio but will be able to post error message shortly, if necessary.)
How can I - from the MainActivity's onActivtyResult() or elsewhere - ensure that the saved instance of the first fragment is returned to and updated, regardless of which fragment is currently visible when the option was selected? Or is it just as easy to create a new instance of the first fragment? (It would be created with the updated information automatically.)
you can get existing fragments through the FragmentManager from the Activity.
see here how to do this.
I have an Android project for which I am creating a custom tab view. I have structured the main Activity (FragmentActivity) in such a way that it has a tab bar at the bottom of the screen with a FrameLayout above it. Each option on the tab creates a new Fragment (relating to that option). Now, to prevent recreation of fragments each time an option is clicked, I store the fragment in an instance variable in the activity. So, when a tab option is clicked, I check if its fragment is already created, if it is not already created, I create and add it to the FrameLayout (and hide any existing fragment), otherwise, I just hide the existing fragment (stored in an instance variable called currentlyViewedFragment) and show the already created fragment that matches the clicked option.
Also when the onCreate() of the activity is called, I set the initial tab to be the home tab (one of the tabs).
This works great, except when the activity is recreated (due to orientation changes). Here, I think the instance variables (essentially pointers to already created fragments) loose their value and are set to null. This causes the home tab to be created and be overlayed on the restored view. I also know that you can save state using the bundle passed to onSaveInstanceState and restore it using onRestoreInstanceState. But the bundle needs to contain data which is serialisable. However, these instance variables are merely pointers! How do I restore their values?
NOTE: this problem is solved below in a comment posted by me.
Thanks.
The answer to your problem is using the bundle for state restoration. Create a class in where you can put the variables and is serializable so you can put the its object to the bundle. Or you may also use SharedPreferences to store the instance variables' value in the phone storage. I hope you got idea from my weird answer.
I have got loader in fragment and it loads data on background. After data are loaded, I fill edittexts with that informations. Problem is that if user changes something in edittexts and rotate screen, onLoadFinished is called again and edittexts are replaced with loaded information. I solve this by adding help variable, if data was already loaded .. But when i replace this fragment with other, rotate screen back and forth and press back button, edittexts are empty. Fragment is set to retain instance true. It looks like views lost its state when fragment is on backstack. Anyone familiar with this?
You shouldn't use the retain state.
But the proper way to do so it to save the save using the Bundle and restore it when you recreate the activity (onCreate Bundle is not new).
Please review the link I've sent you it includes a very specific example.
from the android dev guide:
To properly handle a restart, it is important that your activity
restores its previous state through the normal Activity lifecycle, in
which Android calls onSaveInstanceState() before it destroys your
activity so that you can save data about the application state. You
can then restore the state during onCreate() or
onRestoreInstanceState().
Android Rotation Change
Its possible to retain a Fragment between Activities?
Lets say I have Activity A with Fragment F_Left placed at the left and Fragment F_Right placed at the right. If I want to launch a new Activity and keep Fragment F_Left... how can I do it?
Can I retain Fragment F_Left state between activities?
Note that I want to launch a new Activity because Fragment F_Left is my app menu and Fragment F_Right changes completely the context of the user operations... and my app have many of operations, so it makes sense to have an Activity per operation.
I know its possible to retain Fragment within an Activity, but as Fragment life cycle is closely tied to the container Activity I don't know if this is possible keep Fragment state between Activities.
Since API Level 13 (HONEYCOMB_MR2, June 2011), you can save and restore the state of a fragment across activities.
To save the state, use FragmentManager.saveFragmentInstanceState(), providing a reference to the Fragment whose state you wish to save. The Fragment must be attached at the time you attempt to save its state.
To restore the state, use Fragment.setInitialSavedState() with the return value when you instenciate the same Fragment.
myFragment = new MyFragment();
myFragment.setInitialSavedState(appState.getMyFragmentState());
fragmentManager.beginTransaction().add(R.id.container, myFragment).commit();
You can persist the SavedState object across activities as you would any other object; one way is to subclass Application as shown above (appState is the instance of our subclass).
Based on your response to my comment, I have a slightly different answer. It may not end up being the best answer in your specific situation, I'll let you decide that. :)
Right now you are bundling your fragments in activities because that is what made sense to you, but really, you can probably treat the entire process as one activity and use fragment transactions to hide & show (or create and destroy) fragments as needed.
Since you won't be creating and destroying activities, your menu fragment on the left will be left untouched, and you won't have any problems with its UI state. The set of operations you want to run (which no doubt includes all sorts of different fragments on the right) does not need to be launched in a new activity - but you will have to find a way to manage the logic you need for the fragment transactions (either in your one über-activity or in some kind of OperationsManager class).
I think this will end up being a lot smoother for the users of your application since the single activity just remains running - and you are only changing the parts that actually need to change.
If I want to launch a new Activity and keep Fragment F_Left... how can I do it?
Don't launch a new activity.
Can I retain Fragment F_Left state between activities?
Not automatically. It is not the same fragment. You would pass data between the activities for use by the fragment no differently than you would without any fragments at all.
To potentially answer your original question, if you fire off another activity then I believe that you can save your fragment from your first activity by calling FragmentManager::putFragment(...) when onSaveInstanceState(...) is called and then getting it back later, e.g. in onCreate(...).
However, I have to agree with Mark D's response.
Incidentally I'm doing something similar in that I have a dual pane setup whereby the left pane if fixed with a number of options with each option invoking a different fragment in the right pane. Furthermore selecting an entry in the right pane can result in the right fragment being replaced by another one.
However, I have taken the approach whereby by left fragment is only responsible for displaying and handling responses from the immediate fragment which appears in the right hand pane. Furthermore each right-hand fragment is then responsible for 'replacing' itself with a new fragment and handling results sent back to it. I'm using setTargetFragment, getTargetFragment, and calling onto the target fragment's onActivityResult method to pass results back.
For me the approach I've taken is no different from when my app runs on a phone with a single pane whereby the initial option's activity only knows about the activies it fires off and subsequently these new ones fire off further activies which they know about.
It should be mentioned that my activity in my dual pane app doesn't really do much apart from loading the left pane fragment and I can't quite see the need for a single activity to ever have to manage hundreds of fragments.