I was doing an android application, in which I have two different layouts for the same activity (one for portrait and one for landscape, it is important to say that they are totally different). Well my problem the persistence of data between them, since when changing between portrait and landscape the data is lost, to try to solve my problem I used onSaveInstanceState and change the manifest, but none of them serves in my case. I hope you can help me, regards.
pd. Landscape is in the directory layout-land
mensaje=(EditText) findViewById(R.id.EditTextAlarma); //portrait
horaEdit=(EditText) findViewById(R.id.editTextHoras); //landscape
minutosEdit=(EditText) findViewById(R.id.editTextMinutos); //landscape
segundosEdit=(EditText) findViewById(R.id.editTextSegundos); //landscape
mensajeTimer=(EditText) findViewById(R.id.mensajeTimer); //landscape
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("msj",mensaje.getText().toString());
outState.putString("hora",horaEdit.getText().toString());
outState.putString("min",minutosEdit.getText().toString());
outState.putString("seg",segundosEdit.getText().toString());
outState.putString("msjT",mensajeTimer.getText().toString());
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
String m=savedInstanceState.getString("msj");
String h=savedInstanceState.getString("hora");
String mn=savedInstanceState.getString("min");
String s=savedInstanceState.getString("seg");
String mt=savedInstanceState.getString("msjT");
mensaje.setText(m);
horaEdit.setText(h);
minutosEdit.setText(mn);
segundosEdit.setText(s);
mensajeTimer.setText(mt);
}
Override this two methods from your activity
Then when orientation changes just get the value in onRestoreInstanceState and set it to xml widget
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//SAVE YOUR DATA HERE
outState.putString("key","Value");
//YOU CAN SAVE ANY TYPE OF DATA HERE AND RETRIVE
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
//RETRIVE YOUR DATA HERE
String value=savedInstanceState.getString("key");
//SET VALUE TO XML HERE
Log.d("Value saved is:",value);
}
Related
In one of Activities I have HashSet<Integer> mSelectedPositions. I want to save state of this set on screen rotation.
#Override
protected void onSaveInstanceState(#NotNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(SELECTED_TYPES_POSITIONS, mSelectedPositions);
}
And restore it
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState!= null && savedInstanceState.containsKey(SELECTED_TYPES_POSITIONS)){
mSelectedPositions = (HashSet<Integer>) savedInstanceState.getSerializable(SELECTED_TYPES_POSITIONS);
}
...
}
The problem is, getSerializable(..) returns an empty HashSet, even then it wasn't empty in putSerializable(..).
What's even weirder, I have almost the same code (with other keys) in other Fragments, and it works fine.
Don't know if matters, but activity in question is a child of MainActivity.
Upd
Part of the problem is in selection flow. On destroy of activity action mode is finished.
#Override
protected void onDestroy() {
if(mActionMode != null){
mActionMode.finish();
}
super.onDestroy();
}
Which triggers
#Override
public void onDestroyActionMode(ActionMode mode) {
mAdapter.clearSelections();
mActivity.nullifyActionMode();
}
in SelectionCallback.
I think, next thing happens:
1. I put mSelectedPositions in outState Bundle, it stores reference
2. Activity is destroyed
3. SelectionCallback clears mSelectedPositions
4. Actual serialization happens with empty HashSet.
So I made some changes — new HashSet with copy of mSelectedPositions data
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(SELECTED_TYPES_POSITIONS, new HashSet<>(mSelectedPositions));
}
And it works like it should.
Upd2
In Fragments I call mActionMode.finish() in onDetach(), which is not called on screen rotation, so mSelectedPositions there remains intact.
Try putting a Json instead of raw HashMap
#Override
protected void onSaveInstanceState(#NotNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(SELECTED_TYPES_POSITIONS,new Gson().toJson(mSelectedPositions));
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState!= null && savedInstanceState.containsKey(SELECTED_TYPES_POSITIONS)){
String data = savedInstanceState.getString(SELECTED_TYPES_POSITIONS);
if(data != null){
mSelectedPositions = new Gson().fromJson(str, new TypeToken<HashSet<Integer>>() { }.getType())
}
}
...
}
The funny thing is that serialization of outState happens after onDestroy() call. And I was erasing data passed to outState in onDestroy.
So, there are two ways to fix that:
• pass copy of data to outState
• don't erase data in onDestroy
Opted for second option. Erasing might be required in some cases in onDetach() of Fragments, but it is not necessary with Activity.
In my android app, I am trying to solve an issue with orientation change.
I have a main layout where I have two buttons. On click of the first button (default text on this button is "Select a category"), a dialog box appears with a category list with categories displayed as radio buttons. After the user selects a category, the selected category name appears on the button. Now when I change the orientation in the emulator, the Button text gets reset again.
I have used onSaveInstanceState() like below.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initialization code
categoryList=(Button)findViewById(R.id.category_selection);
if (savedInstanceState != null)
{
System.out.println("savedInstanceState---
"+savedInstanceState.getString("bundle_category_name"));
categoryName=savedInstanceState.getString("bundle_category_name");
categoryList.setText(categoryName);
}
else
{
categoryList.setText(R.string.category);
}
// remaining code
}
#Override
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
// Save selected category name
System.out.println("saving category name "+categoryName);
outState.putString("bundle_category_name", categoryName);
}
I am able to get the category name back in onCreate(), the sysout prints correctly. But it is not getting set as the button text after change in orientation.
Please let me know if I am doing anything wrong.
Thanks
Add android:configChanges="orientation|screenSize" in your Android Manifest file.
<activity android:name="YourActivity"
...
android:configChanges="orientation|screenSize"
.../>
Saving and restoring the data works using two Activity lifecycle methods called onSaveInstanceState() and onRestoreInstanceState().
To save the state information override onSaveInstanceState() method and add key-value pairs to the Bundle object that is saved in the event that your activity is destroyed unexpectedly. This method gets called before onStop().
To recover your saved state from the Bundle override onRestoreInstanceState() method. This is called after onStart() and before onResume(). Check the below code
public class MainActivity extends Activity{
private static final String SELECTED_ITEM_POSITION = "ItemPosition";
private int mPosition;
#Override
protected void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
// Save the state of item position
outState.putInt(SELECTED_ITEM_POSITION, mPosition);
}
#Override
protected void onRestoreInstanceState(final Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Read the state of item position
mPosition = savedInstanceState.gettInt(SELECTED_ITEM_POSITION);
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
// Save UI state changes to the savedInstanceState.
// This bundle will be passed to onCreate if the process is
// killed and restarted.
savedInstanceState.putBoolean("MyBoolean", true);
savedInstanceState.putDouble("myDouble", 1.9);
savedInstanceState.putInt("MyInt", 1);
savedInstanceState.putString("MyString", "back to Android");
// etc.
}
To Retrieve the data
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore UI state from the savedInstanceState.
// This bundle has also been passed to onCreate.
boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");
double myDouble = savedInstanceState.getDouble("myDouble");
int myInt = savedInstanceState.getInt("MyInt");
String myString = savedInstanceState.getString("MyString");
}
Here is a re-occurring problem that I haven't found a good solution for in the past.
My application is based on a single activity that has multiple child fragments.
What i want to do:
In some of my fragments, I want to take a picture with the phones own camera-app and both show the image for the user and then upload it to my server.
What i do now
Now, i am calling StartActivityForResult with my camera intent which works fine. Then i receive what i need from onActivityResult and are able to show the taken image in an image view and also send it to my server.
The problem
Some times when my onActivityResult is called. My fragment has been uninitiated or just flushed from memory by the OS (As i understand it).
This means that variables now has null-references.
What i have read from similar issues is that OnCreateView() is supposedly to be called before OnActivityResult().
So what I am trying to do here is to save the fragments state to its Arguments in my onDestroyView() and onSaveInstanceState() and then try to restore variables such as the temporary Camera Image FilePath. Here however, the fragment seems to initiate the Fragment with a new Bundle and not the one i've created for it, and causes my app to crash due to my camera file is null.
This is also hard to test as this just happens some times at random.
Code
saveState() is called from onDestroyView() and onSaveInstanceState()
#Override
protected Bundle saveState() {
Bundle state = new Bundle();
state.putSerializable("tempCameraFile", tempCameraFile);
return state;
}
restoreStates() is called in the end by onCreateView()
private void restoreStates(){
tempCameraFile = (File)savedState.getSerializable("tempCameraFile");
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 7777 && resultCode == Activity.RESULT_OK) {
setPendingImage(tempCameraFile);
}
}
private void setPendingImage(File imageFile){
try {
Bitmap bitmap = PhotoUtils.decodeFile(imageFile.getPath(), Utils.convertDpToPixel(40, mActivity));
if(bitmap != null) {
buttonImageChooser.setImageBitmap(bitmap);
}
} catch(NullPointerException npe){
npe.printStackTrace();
Log.d(getClass().getSimpleName(), "imageFile NULLPOINTER!!!! WHYYYY!?");
}
}
#Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
saveStateToArguments();
}
#Override
public void onDestroyView() {
super.onDestroyView();
saveStateToArguments();
}
private void saveStateToArguments() {
if (getView() != null)
savedState = saveState();
if (savedState != null) {
Bundle b = getArguments();
b.putBundle("savedState", savedState);
}
}
I really hope there is an obvious thing I am doing wrong when using fragments and that someone are able to help me out.
This has been a reoccurring problem that I have solved with a really ugly implementation of destroying and re-creating fragments from my Activity, but I now want to do this the right way.
The problem is you are not saving your state at all.
#Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
saveStateToArguments();
}
The bundle outState contains all values which will be saved, but your method
saveStateToArguments(); saves the values in another bundle.
The outState and your bundle are not related, so nothing will be saved.
Besides there is no need to call the saveStateToArguments(); in the onDestroyView 'cause the onSaveInstanceState will be called.
So simply change your code to the following:
#Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putSerializable("tempCameraFile", tempCameraFile);
}
And restore the state in the method onRestoreInstanceState
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null) {
tempCameraFile = (File) savedInstanceState.getSerializable("tempCameraFile");
}
}
Because the lifecycle is the following:
onCreate
onStart
onRestoreInstanceState
onActivityResult
onResume
See State of Activity while in onActivityResult question
Use activity to start the camera app and use activity's onActivityResult to make sure if the fragment exists. If it doesn't reinitialise the fragment.
getActivity().startActivityForResult(intent);
The problem is the system kill background activities on low memory.
Solution :
Save state of Activity or Fragment
/**
* Handled take camera photo on low memory maybe activity on background killed, need to save state.
*/
private Uri cameraMediaOutputUri;
#Override
public Uri getCameraMediaOutputUri() {
return cameraMediaOutputUri;
}
#Override
public void onSaveInstanceState(#NonNull Bundle outState) {
outState.putParcelable("cameraMediaOutputUri", cameraMediaOutputUri);
super.onSaveInstanceState(outState);
}
Restore the state and here is the trick as restoring state on Activity is different from Fragment.
Restoring Activity State
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState !=null && savedInstanceState.containsKey("cameraMediaOutputUri"))
cameraMediaOutputUri = savedInstanceState.getParcelable("cameraMediaOutputUri");
}
Restoring Fragment State Fragment Life Cycle
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState !=null && savedInstanceState.containsKey("cameraMediaOutputUri"))
cameraMediaOutputUri = savedInstanceState.getParcelable("cameraMediaOutputUri");
}
I have a few CheckBox elements inside one of my Fragments.
Every time I leave this Fragment it seems to nor save or restore the checked state of each one provided by the user.
In the FragmentList example you can find:
CheckBox check1;
boolean active;
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("state1", check1.isChecked());
}
Which you can use later like this:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
// Restore last state for checked position.
check1.setChecked(savedInstanceState.getBoolean("state1"));
}
}
But somehow the CheckBox elements don`t save their state.
Is this the correct approach I should take?
Unless you're keeping your Fragment reference alive through the lifecycle of the application, it should be fine to save its state in onSaveInstanceState and restore it in onActivityCreated.
One important point, though, is also to save and restore that state in the Activity level by doing like:
public void onCreate(Bundle savedInstanceState) {
...
if (savedInstanceState != null) {
// Restore the fragment's instance
mFragment = getSupportFragmentManager().getFragment(
savedInstanceState, "fragKey");
...
}
...
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save the fragment's instance
getSupportFragmentManager().putFragment(outState, "fragKey", mContent);
}
Please check to see how your Activity is behaving in your scenario.
I have an app in which user can draw using finger. But after drawing if user changes oreintation of screen, bitmap looses all the arcs. I tried to set in that activity
onConfigchange="screensize|orientation" but it did'nt worked
#Override
protected void onSaveInstanceState(Bundle outState)
{
outState.putInt("value",10);
super.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
int mySaveValue=0;
if(savedInstanceState!=null)
mySaveValue = savedInstanceState.getInt("value");
super.onRestoreInstanceState(savedInstanceState);
}
Use onSaveInstanceState(Bundle outState) to save the state of your drawing, save every value which will be used to draw it again.
when orientation is changed, you will get a callback in onRestoreInstanceState, fetch all the values from bundle and set to your view.
e.g, if you need to save an int value and retrieve it later, do following:-