My program runs an activity on startup, afterwards it sends an Intent opening another activity. The first time this happens, I want to save the information from the Intent to the savedInstanceState so whenever the app is opened again that information is available. The code looks like this:
savedInstanceState.putString("name", getIntent().getStringExtra("name"));
savedInstanceState.putString("font", getIntent().getStringExtra("font"));
savedInstanceState.putInt("background", getIntent().getIntExtra("background", R.drawable.bg1big));
However I continue to get a NullPointerException saying
Attempt to invoke virtual method 'void android.os.Bundle.putString(java.lang.String, java.lang.String)' on a null object reference.
You basically need to overwrite onSaveInstanceState() and onRestoreInstanceState() to store and retrieve the values that you want. Have a look at this answer - https://stackoverflow.com/a/151940/1649353
savedInstanceState is what you were given if something was saved last time - it's what was reloaded. even if it isn't null, you shouldn't add anything to it, it won't persist. Do this instead:
#Override
public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
bundle.putString("name", mName);
bundle.putString("font", mFont);
bundle.putInt("background", mBackground);
}
And then in onCreate and onRestoreInstanceState you can read the values and populate those variables you'll later save
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mName = savedInstanceState.getString("name");
mBackground = savedInstanceState.getString("background");
mFont = savedInstanceState.getString("font");
}
Related
So im having some trouble restoring the state of my Activity.
At this point I figure that its probably a problem with my understanding rather then anything else.
My goal is to move from my MainActivity to a Main2Activity.
Am I correct in thinking that when a user moves from one page to another, it should be done by changing Activity via Intent?
I am doing this like so:
The onCreate() for my MainActivity has this in it.
Button currentButton = (Button) findViewById(R.id.button2);
currentButton.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View view) {
setContentView(R.layout.activity_main2);
Intent nextIntent = new Intent(getApplicationContext(), Main2Activity.class);
startActivity(nextIntent);
}
}
);
Which as I understand should call onCreate(), onStart() and onResume() for Main2Activity, then onSaveInstanceState() for MainActivity, then onStop() for MainActivity.
Ive overloaded all those functions with logging and seen that indeed they are being called and in that order.
Here is my onSaveInstanceState() for MainActivity:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
System.out.println("onSaveInstanceState called, saving state");
savedInstanceState.putInt("mySuperUniqueKey", testInt);
super.onSaveInstanceState(savedInstanceState);
}
Once in Main2Activity, I return back to MainActivity in the same way. I.e. findViewById() the button, overload its onClickListener(), create a new Intent and start it.
Then MainActivity class's onCreate() has this :
if (savedInstanceState != null) {
System.out.println("savedInstanceState is not null");
testInt = savedInstanceState.getInt("mySuperUniqueKey");
} else {
System.out.println("savedInstanceState is null");
}
When returning back the MainActivity from Main2Activity, I can see from the logging that onCreate(), then onStart(), then onResume() for MainActivity is called, then onStop() for Main2Activity. Unfortunatly the logging shows that savedInstanceState always comes back as null.
To add to this, when in the emulator, switching the orientation back and forth causes this to work perfectly; savedInstanceState is not null and features the saved testInt.
Thus I figure its a problem with my understanding and that there must be something im missing.
My gradle has minSdkVersion set to 16, and targetSdkVersion set to 28. Am I maybe targeting too low a minSdkVersion?
I have read through the "Understand the Activity Lifecycle" on the official android developer documentation but still cant get it.
https://developer.android.com/guide/components/activities/activity-lifecycle
I did find similar problems but none of them match my situation exaclty, also the solutions they have suggested I am already doing anyway.
Any insight would be greatly appreciated, thanks in advance.
The saved instance state bundle is intended to save the state of the current activity across things like orientation changes. It is not designed to persist across activities. You should use Intent#putExtra:
nextIntent.putExtra("mySuperUniqueKey", testInt);
Then, in your next activity, access this passed value using:
int testInt = getIntent().getIntExtra("mySuperUniqueKey");
I'm having a lot of trouble with Android Fragments, and I don't know why.
I want to keep an object in memory whenever I pause the app (onPause()).
I have a MapView with some layers. And I want to keep those layers, so the map doesn't have to reload from scratch and recreate them whenever I pause and resume the app.
The thing is, I can't save them with onSaveInstanceState(). They are objects, not primitives. They are also from a library, so I can't make them implement Serializable or Parcelable.
I want to find a solution without resorting to:
android:configChanges="orientation|screenSize">
to my Activity, since it is considered bad practice. Also, it doesn't work for when you pause and resume the app.
I also tried
this.setRetainInstance(true); // retain this fragment
on my fragment's onCreate(), but I would also like to avoid it. It doesn't work anyway.
After much trial, error and testing, I found out that my fragment's onSaveInstanceState() doesn't even run. I can't even keep a simple boolean whenever I pause and resume the app.
I read:
Saving Android Activity state using Save Instance State
https://developer.android.com/training/basics/activity-lifecycle/recreating
savedInstanceState is always null
Amog many other posts and, of course, the Android documentation.
Some of my code:
Creating the fragment:
navFragment = FragNavigation.newInstance(); // keeping the reference to the navFragment
// setting up the viewpager
ViewPager viewPager = findViewById(R.id.vpMainViewPager);
MainPagerAdapter mainAdapter = new MainPagerAdapter(getSupportFragmentManager(), this);
mainAdapter.addFragment(navFragment);
viewPager.setAdapter(mainAdapter);
Trying to save a simple boolean in the instance state (remember: this doesn't even run):
#Override
public void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
Log.e(TAG, "onSaveInstanceState: is map loaded? " + mapIsLoaded );
outState.putBoolean("mapIsLoaded", mapIsLoaded);
}
And trying to load it:
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setRetainInstance(true); // retain this fragment
Log.e(TAG, "onCreate: null? " + (savedInstanceState == null) );
if (savedInstanceState != null)
mapIsLoaded = savedInstanceState.getBoolean("mapIsLoaded", false);
}
What am I missing? I'm clearly not understanding something. Why is it so hard to keep values when you pause the app?
I would suggest storing the MapView layers using a ViewModel as per Architecture Components. If that is not an option, you can manually store and retrieve objects using the Activities getLastNonConfigurationInstance.
#Override
public void onPause() {
/**
* store your data
*/
super.onPause();
}
#Override
public void onResume() {
/**
* retrieve your data
*/
super.onResume();
}
I'm having some issues with the onSaveInstanceState, but it may be because I misunderstand how it works.
I have a Arraylist i want to save when I switch activities then restore when i come back.
so i have this method
#Override
protected void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
bundle.putStringArrayList("History", History);
and my onCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if( savedInstanceState != null ) {
History = savedInstanceState.getStringArrayList("History");
}
}
For some reason this loop is not being initliased
if( savedInstanceState != null ) {
History = savedInstanceState.getStringArrayList("History");
}
I'm pretty sure its soemthing fairly simple but I'm still quite new to Java.
If you are simply switching activities, it will stay 'alive' in the background (unless the OS decides to kill it off to free memory). Read this article for more information on Activity state
In this case, onCreate() will not be called when the Activity resumes, as it has already been created and is simply been onResume()-ed.
You should look at another method of storing your History values such as in SharedPreferences, a database or in a persistent object on the application class instance (whatever suits your preference) in your onPause() method and restore those values in onResume().
onSavedInstanceState() is used for when an activity is killed like in an orientation change or OS kill.
I want to save some variables after exiting activity which are set during the lifetime of my android activity and show them when I launch activity again but I don't seem to manage to get things working. Here's how I do it:
I created an integer variable "test":
public class MainActivity extends Activity {
int test = 1;
Then I write a method to change this varibale's value by pressing a button:
public void changeValueTest(View view) {
this.test = 2;
}
Then I use onSaveInstanceState() method to save the changed value:
static final String TEST = "test variable";
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putInt(TEST, this.test);
super.onSaveInstanceState(savedInstanceState);
}
Then in onCreate() method I put this code to get and show the changed "test" value:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
this.test = savedInstanceState.getInt(TEST);
TextView textView1 = (TextView)findViewById(R.id.textView1);
textView1.setText("Current test value is: " + test);
}
}
So I open the application, press the button to change the "test" value from 1 to 2, then exit the application, wait until it's properly removed from memory (when Application Manager doesn't show it in "Cached processes" window), start the application again and textView1 view shows 1 instead of 2. What am I doing wrong? Please help! Thanks!
What am I doing wrong?
Nothing. Instance state does not cover the scenario that you are describing.
Mostly, instance state is used in configuration changes (e.g., screen rotation). Secondarily, instance state is used if the user leaves your app by means other than "exit" (by which I assume you mean BACK) and returns to you via means like the recent-tasks list.
As documented in Developer.android , Saved instance only saves your Activity state, It will not save your variable as you wanted,
I would suggest you to use SharedPreference instead.
so i have this code in my OnsavedInstanceState
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
String [] a={"haha"};
savedInstanceState.putStringArray("MyStringarray", a);
Toast.makeText(context, "Saved array", Toast.LENGTH_SHORT).show();
}
and i have this code in my onCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState==null){
Toast.makeText(this, "not there", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "is there", Toast.LENGTH_SHORT).show();
}
}
how come the toast always says not there? i opened the app then switched to another app and it showed the toast saved array but when i reopen the app it says not there even though the bundle should have the string array containing "haha".
Many thanks!
In onSaveInstanceState() you're modifying savedInstanceState and not saving this modified object. If super does a copy of your Bundle, then it will not save this modification.
Try calling super.onSaveInstanceState(savedInstanceState); at the end of the method instead.
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
String [] a={"haha"};
savedInstanceState.putStringArray("MyStringarray", a);
super.onSaveInstanceState(savedInstanceState);
Toast.makeText(context, "Saved array", Toast.LENGTH_SHORT).show();
}
The problem might be in how you have your activities defined in your manifest. For instance if your activity has the setting android:clearTaskOnLaunch="true" I don't think you will receive the saved bundle. See http://developer.android.com/guide/topics/manifest/activity-element.html for details on the various activity settings.
You might also check the other overridden methods. For example in you override one and do something odd you could mess the activity stack up. Do you call finish() anywhere in you code, if so remove it and see what happens.
Do not confuse this method with activity lifecycle callbacks such as onPause(), which is always called when an activity is being placed in the background or on its way to destruction, or onStop() which is called before destruction. One example of when onPause() and onStop() is called and not this method is when a user navigates back from activity B to activity A: there is no need to call onSaveInstanceState(Bundle) on B because that particular instance will never be restored, so the system avoids calling it. An example when onPause() is called and not onSaveInstanceState(Bundle) is when activity B is launched in front of activity A: the system may avoid calling onSaveInstanceState(Bundle) on activity A if it isn't killed during the lifetime of B since the state of the user interface of A will stay intact.