I have one activity which has more than 20 fields, most of these fields will prompt user to set data.
Now the problem with the Configuration changes. If user set all the fields & he/she changed screen orientation, then all the fields will be reset because the activity will restart.
If I have only few fields means, then I would have gone with onSaveInstanceState() & onRestoreInstanceState().
But how to handle these many fields? Whether I have to go by storing all the fields? or Is there any better approach?
Try this way
<activity
android:name=".ActivityName"
android:configChanges="orientation|screenSize|keyboardHidden"/>
While you can prevent the activity from rotating to avoid the problem, this should only be done in special circumstances. Also, there are other situations where configuration changes can take place and cause problems. For a full discussion, see this: Why not use always android:configChanges="keyboardHidden|orientation"?
So my suggestion is that instead you create a holder class that implements Parcelable. Then on onSaveInstanceState(Bundle outState) simply call outState.putParcelable(key, yourParcelableObject). You would still need to update the corresponding fields on and this class but at least you would avoid having several keys and calling individual put to the bundle.
add android:configChanges="keyboardHidden|orientation|screenSize" to activity tag in manifest file but that is not best way please read Why not use always android:configChanges="keyboardHidden|orientation"? and http://developer.android.com/guide/topics/manifest/activity-element.html#config and http://developer.android.com/guide/topics/resources/runtime-changes.html for selecting best way for yourself here is a good example for using from parcle .
Related
I have a fragment, which contains many EditTexts.
And when I rotate the device the EditText goes blank. The fragment is not saving its state/value. But at the same time if I use that fragment layout for activity it stores the EditText's state.
And yes I've given the IDs to each EditText, even to each view if that matters.
I know I can use saveInstanceState to save those values but is there any other way to do it? Cause there are almost 20 EdiText in that fragment, so should I use saveInstanceState, will it be okay to save these many variables/values in saveInstanceState?
Update:
I was recreating the fragment in activity on orientation change, so that was the reason, EditText was unable to save its state.
Such a silly mistake!
So now I just used saveInstanceState like following:
if (savedInstanceState == null) {
initialiseNewTaskFragment();
}
And that's it. EditText is saving its state now.
Thank you JorgeGil for saving my time!
Well this is a fairly loaded question lol.
So let's start with a few points.
First, you can of course handle your own lifecycle change if you choose to NOT allow Android to reset your lifecycle on device rotate.
android:configChanges="orientation"
Use that flag in your manifest if you want to retain everything and handle your own rotation changes. However, if you have a layout-land folder with different XML files, you will not want to do this.
Yes of course you can do fragment.retainInstance when nested in Activities to get it to retain values. However, retaining populated Elements with values is not something you can just natively expect it to do as the UI elements were completely redrawn, so something has to tell it to redraw it again.
So if you are going old school and you are actually still doing findViewById and myText.setText('some Stuff'). Then you may find some time savings in using a library like icepick.
https://github.com/frankiesardo/icepick
However, the BEST option by a mile is to modernize your coding practice to use DataBinding. This allows you to not care about the UI interactions anymore as the values are bound to your Fragment or Activity or Model values by default and can be done with 2-way binding. This ensures databinding always populates with the value that was last updated.
Imagine you have an object of
public class Student implements BaseObservable{
String firstName;
}
Then in your xml you have
editText
android:text="#={student.firstName}"
Obviously there is a little more, like you need to set your student object in the onCreate to ensure it is in the XML for using. But when the user modifies the student firstname it is retained in the model, and redrawn automatically into the Edit Text.
This is your best solution, but depends on how invested you are in the future binding techniques of Android development or if you just prefer to go status quo to get across a finish line.
Hope that helps.
Add this in your Activity tag on your AndroidManifest.xml to avoid the recreation of the Activity and you won't lose the data.
android:configChanges="orientation|screenSize"
I'm a little confused about the Activity being destroyed and recreated when the user's device is rotated.
I've been reading around, and I understand the rationale for doing so (it basically 'forces' the developer to make sure they haven't 'missed' anything upon rotation/language/other changes)
I'm happy to respect best practice if it is seen as such, however it begs the question:
How do I 'remember' the state of the game/app, so that when the screen is rotated I have something from which to re-generate what the user was looking at?
From what I can see, absolutely everything is destroyed, the base class constructor runs and all variables in the Activity are 'null'.
I suspect the 'savedInstanceState' (Bundle class) is where I would collect that data, but reading around it only seems to be used for when the app is closed from lack of resources (and a few other extremely fringe cases)
Am I misinformed or misunderstanding the purpose of savedInstanceState? Is it wise to abandon best practice (letting the Activity be destroyed) if I'm mindful enough to not miss anything upon rotation? Thanks in advance for any advice.
I should note this question applies to game programming (I'm not using a layout XML)
Do you need your activity to be recreated? Is there work you want to do on rotation? savedInstanceState is where you would store data to be passed to the recreation of the Activity, but since you aren't using XML layouts you may consider just adding android:configChanges="orientation" to your activity in the manifest. This will give you manual control over what happens during rotation change.
In additional to my original comment, I would override config changes for keyboard being show as well:
android:configChanges="orientation|keyboardHidden"
If there is work you want to do on rotation change you can override onConfigChange and do anything you need there.
It's hard to say that there is a time when you should always override config changes, but I often do it when I have no dependency on resource folders that are size or orientation specific and I'm doing a lot of work that would take too much time to recreate.
There are other best practices to store data while activitiy config changes.1. Developer Doc Handling Runtime Changes2. Alex Lockwood : Handling Configuration Changes with Fragments, This will answer all your questions reagarding config change and storing data.
Impt:
Fragment file to store data. You must set setRetainInstace(true) in order to store data and retrieve while your activity config changes.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// retain this fragment
setRetainInstance(true);
}
I have activity the contains a ListView, and this listview is filled with data from a web service in onCreate() function ( using AsyncTask). When the screen orientation changes the activity is re-created, I don't want that. how to keep saved after changing the orientation
You need to add this in the Activity in AndroidManifest.xml. Just adding "orientation" will not work on all devices.
android:configChanges="orientation|screenSize"
Set android:configChanges="orientation" in your AndroidManifest.xml for the activity.
Although the other answers suggest using android:configChanges, I would say this is really only a last resort option because it means resources for different orientations will not get loaded automatically.
Instead you should use the onSaveInstanceState or onRetainNonConfigurationInstance functions of your activity. (If you use fragments, you should use setRetainInstance instead of the latter option.)
Another option would be to use a ContentProvider to store the data you download using the AsyncTask into a database so it wouldn't need to be re-downloaded anyway.
You should read this for more information.
I have Activity with ListView inside it and in the onCreate method of the Activity I have code for populating the Data of the ListView this Data is a server based and so populating includes calling Network URLs. I have the ArrayAdapter of the ListView in the Same Activity Class.
Now the Issue I'am facing is that, in Rest all scenarios my Activity is behaving in a proper way but when the Orientation [ Portrait to Landscaped or other way round] is taking place the Data is Getting lost and Newer Data calls are Required to Populate the Same Old Data now this is something that is not intended out the code how should I deal with it.
Android will stop and restart your activity unless you've told it you will handle orientation changes yourself. It does this so that you can specify different resources (such as layouts) that are orientation-specific (among other reasons).
You need to add android:configChanges="orientation" to your activity delcaration in your AndroidManifest.xml, and you need to override onConfigurationChanged(). I don't believe you need to do anything special inside onConfigurationChanged(), simply implementing it should do the trick.
For those targeting API 13 or higher, "screenSize" should also be used. If that is your case, add
android:configChanges="orientation|screenSize"
to your Android manifest.
More information here.
AFAIK the whole Activity gets recreated on an orientation change!
The same is true if you switch to anoter app and return back later.
I would suggest to store the data is the SharedPreferences or serialize them into XML and store them.
Another possibility could be to register your own service that stores the data in memory and the activity poluplates the data from the service.
Why not saving any data into a parceable and if the bundle you get in onCreate contains a saved state of data re-set the list adapter? Here is a nice code sample on this: http://blog.cluepusher.dk/2009/10/28/writing-parcelable-classes-for-android/
android:configChanges="orientation|screenSize"
this code will work only if we don't have another layout for landscape mode!
I read up on how Android handles "configuration changes" - by destroying the active Activity.
I really want to know from Android Team why this is. I would appreciate an explanation on how the reasoning went, because I don't understand it. The fact that it acts in that way puts us all, as I see it, in a world of pain.
Lets assume you have a Activity which presents a number of EditText:s, checkboxes etc. If a User starts to fill that form with text/data and then changes orientation (or get a Phonecall), then all input the User made is gone. I haven't found any way to preserve state. That forces us to make extremely painful coding to not lose all data.
As I see it, you need another "non-Activity" class (or "value-holding" class perhaps) that has one field for each "form element" (EditText, checkbox etc).
For every single "form element" that exists, you then need to attach an Event like "onChanged" (or onTextChanged or something like that) that updates the corresponding field in the "value-holding" class to make sure that for every single character you type (in a EditText for example) is saved at once.
Perhaps you can use some listener (like "onDestroy" or something) and then fill the value-holding class with data.
I have also found this piece of info where they talk about using Bundle, onSaveInstanceState and onRestoreInstanceState, but that also mean that the programmer has to manually save and then later put back the values in the correct place? This approach is a bit less messier than my suggestions above, but still not very nice.
Can someone tell me that I am totally wrong and that this is not how it works and that I totally missed some vital information?
You should read the Application Fundamentals (specifically, Activity lifecycle). Since Activitys must be able to handle being killed at any time due to memory contraints, etc. it's just a cleaner way to handle rotations without adding too much complexity - instead of checking every resource for an alternate resource, re-structuring the layout, etc. you just save your essential data, kill the activity, re-create it, and load the data back in (if you're willing to deal with the extra complexity of managing this yourself, you can use onConfigurationChanged to handle the configuration change yourself.) This also encourages better practices - developers have to be prepared for their Activity to be killed for orientation change, which has the (good) consequence of being prepared for being killed off by memory contraints also.
The contents of an EditText will be saved for you automatically when rotating the screen if you put an android:id attribute on it. Similarly, if you display dialogs using Activity#showDialog, then the dialogs are reshown for you after rotating.
on why part - short answer - because you might have resources that needed to be changed as you've rotated the phone. ( Images, layout might be different, etc )
On save - you can save you stuff to bundle and read it back.
#Override
protected void onSaveInstanceState(Bundle outState) {
String story_id = "123"
outState.putString(ContentUtils.STORYID, story_id);
}
or you can use onRetainNonConfigurationInstance () as described here
http://developer.android.com/reference/android/app/Activity.html#onRetainNonConfigurationInstance()
Finally if you don't have anything you want to handle during rotation - you can ignore it
by putting this into your activity in manifest
android:configChanges="keyboardHidden|orientation"
In general, i would read trough article from url above couple of times, until lifecycle is crystal clear.
#Alex's approach above pointed me to a really, really useful solution when using fragments:
Fragments usually get recreated on configuration change. If you don't wish this to happen, use
setRetainInstance(true); in the Fragment's constructor(s)
This will cause fragments to be retained during configuration change.
http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean)