How to get the bundle that is given to this method on request (Bundle outState)?
#Override
protected void onSaveInstanceState(***Bundle outState***) {
super.onSaveInstanceState(outState);
// Only if you need to restore open/close state when
// the orientation is changed
if (adapter != null) {
adapter.saveStates(outState);
}
}
in Bundle instance you can pass the data and get it back in onCreate() method. like following
outState.putString("key1", "data1");
outState.putBoolean("key2", "data2");
outState.putInt("key3", "data3");
and in onCreate get it like following
if (savedInstanceState != null){
data_1 = savedInstanceState.getString("keys1");
data_2 = savedInstanceState.getBoolean("keys2");
data_3 = savedInstanceState.getInt("keys3");
}
You can get saved bundle back using below method:
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
// get your saved bundles back here
}
Just refer this developer page, you will get clear idea about this
It's the Bundle sent in the OnCreate method in your activity.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
savedInstanceState.getString("bla");
}
}
Note that you'll have to check for null, because the first time you create your activity it will be null, since there was no previous state.
see https://developer.android.com/guide/components/activities/activity-lifecycle.html#oncreate for more information
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 2 serializable objects that I want to retain after my fragment is rebuilt. Therefore I saved them during onSaveInstanceState (the objects are not null here):
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(RENDERER, renderer);
outState.putSerializable(SERIES, series);
}
In the onCreate method of the fragment I try to get them out of the Bundle:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
renderer = (DefaultRenderer) savedInstanceState.getSerializable(RENDERER);
series = (CategorySeries) savedInstanceState.getSerializable(SERIES);
}
}
The problem is that "renderer" and "series" are always null after calling getSerializable. Any ideas why?
Did you override onSaveInstanceState method in FragmentActivity that hosts this fragment? If you're, then make sure that it should call super.onSaveInstanceState(Bundle).
I have the following code in one activity:
in= new Intent(ThisActivity.this,AnotherActivity.class);
imgarr = new ImageView[55];
imgarr[0]=(ImageView) findViewById(R.id.species3);
imgarr[0].setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
b.putString("specno",Integer.toString(0)); in.putExtras(b);
in.setClassName("com.DuckHuntersJournal","com.DuckHuntersJournal._1_TagKillActivity");
startActivity(in);
}
});
And this code in another:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.menu1tagkill);
if ((savedInstanceState != null) && savedInstanceState.containsKey("specno")) {
Log.e(tag, "intent from species not null");
species.setText(savedInstanceState.getString("specno"));
}
However, savedInstanceState is null.
Why am I not getting any data back from the first activity?
You need to use :
getIntent().getExtras().getString("specno");
in order to get the passed string from the first activity.
EDIT: I'm not sure what you are trying to do... for getting data from another Activity that started the current one you need to use getIntent().getExtras().
For saving your current stat when the Activity goes to background you save the data in the onSaveInstanceState() method and then in the onCreate(Bundle savedInstance) method you get the saved data from the savedInstance parameter.
You'll need to do the following in your receiving Activity:
String species = getIntent().getStringExtra("specno");