This is my scenario. I have an activity that is a directory browser. When the user taps on a file in the list of the activity, it will start another activity that will display the file contents.
The second activity has the default back button in the action bar. When I tap on this, I want the first activity to reappear and show the same directory that was open before.
How do I properly store the location and how do I restore it when the first activity becomes active again?
I tried the code below, but the savedInstanceState object in the OnCreate() method is always null and the else branch will be executed! What is the reason for this?
private String rootFolder = "/";
private String currentDirectory = rootFolder;
#Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putString(getString(R.string.state_current_directory), currentDirectory);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file_picker);
pathDisplay = (TextView)findViewById(R.id.path);
if (savedInstanceState != null) {
String lastDirectory = savedInstanceState.getString(getString(R.string.state_current_directory));
getDirectory(lastDirectory);
}
else {
// THIS BRANCH WILL ALWAYS BE EXECUTED?!?
getDirectory(currentDirectory);
}
}
Related
I have this following code:
public class MainActivity extends AppCompatActivity {
EditText edtInput;
private static final String STATE_RESULT = "state_result";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edtInput = (EditText) findViewById(R.id.edtInput);
}
#Override
protected void onSaveInstanceState(#NonNull Bundle outState) {
outState.putString(STATE_RESULT, edtInput.getText().toString());
super.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(#NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null){
edtInput.setText(savedInstanceState.get(STATE_RESULT).toString());
}
}
}
On Pixel 3 (running Android 12): type something in the EditText, then do a combo of screen rotations, turning on/off the screen, press back to home and open the app again. the user input is still on EditText
On Xiaomi Pocophone F1 (running Android 10) there's a slightly different behaviour: EditText is cleared if you press back and open the app again. but no problem as long as you only turn on/off or rotate the screen.
Not sure if I misunderstood Android activity lifecycle, or this is a bug on the OS. Any help is appreciated.
Before you can start figuring out why it's happening, you need to figure out what exactly is happening.
You should add some logging to see exactly where it fails. Maybe on the F1, the app gets killed before it calls onSaveInstanceState(). Or maybe onRestoreInstanceState() has savedInstanceState == null:
#Override
protected void onSaveInstanceState(#NonNull Bundle outState) {
outState.putString(STATE_RESULT, edtInput.getText().toString());
super.onSaveInstanceState(outState);
Log.d("***", "Saved")
}
#Override
protected void onRestoreInstanceState(#NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d("***", "Restoring: " + (savedInstanceState == null))
if (savedInstanceState != null){
edtInput.setText(savedInstanceState.get(STATE_RESULT).toString());
}
}
And then look at the logs to see what happens on the F1 when you exit the app using the back arrow, and then re-launch it.
Edit: Since it appears that onRestoreInstanceState() isn't being called on the F1, you should probably try to save your app state yourself, instead of relying on savedInstanceState. For example, you can just add an onTextChanged() listener to each of the editText fields, and save the text into SharedPreferences. And you can delete that preference when the user submits the text. You can then restore them in onCreate(). That way, you're completely independent of the lifecycle
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");
}
I put an imageview to load an image of a url, it is when I click on a button it passes to the next url, thus changing the image.
the problem is that when I rotate the screen it returns to the first image displayed.
I tried to do an if with incremented counter but it deletes the variable and returns to the first one again.
someone knows how to save the value of the "next" variable so when the screen rotates it keeps the value saved, or knows another way to keep the last image saved.
api picasso
code complete
private SmartImageView smartImage;
private Button btn;
private int proxima = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_redacao_nota_1000);
if (proxima == 0) {
smartImage = (SmartImageView) findViewById(R.id.meuSmartImage);
smartImage.setImageUrl("http://gabrielmartins70.000webhostapp.com/bao.png");
proxima++;
}
btn = (Button) findViewById(R.id.button18);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (proxima == 1) {
smartImage.setImageUrl("http://gabrielmartins70.000webhostapp.com/2.png");
}
}
});
}}
When your activity is recreated after it was previously destroyed, you can recover your saved state from the Bundle that the system passes your activity. Both the onCreate() and onRestoreInstanceState() callback methods receive the same Bundle that contains the instance state information.
Because the onCreate() method is called whether the system is creating a new instance of your activity or recreating a previous one, you must check whether the state Bundle is null before you attempt to read it. If it is null, then the system is creating a new instance of the activity, instead of restoring a previous one that was destroyed.
Save your int variable like following example does:
static final String STATE_USER = "user";
private String mUser;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
mUser = savedInstanceState.getString(STATE_USER);
} else {
// Probably initialize members with default values for a new instance
mUser = "NewUser";
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putString(STATE_USER, mUser);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
i did a lot of trials before coming here, i need that user find the same values entered in
an activity when he returns to , i did this code but it is not working :
public class ActivityUn extends Activity {
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putString("arm_1", rm_1ts);
savedInstanceState.putString("arm_2", rm_2ts);
super.onSaveInstanceState(savedInstanceState);
}
public void ajouter(View v) {
db.open();
long id = db.insertMENAGE(rm_1ts,rm_2ts); }
EditText rm_1;
EditText rm_2;
String rm_1ts = "";
String rm_2ts = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_un);
rm_1 = (EditText)findViewById(R.id.rm_1);
rm_2 = (EditText)findViewById(R.id.rm_2);
if (savedInstanceState != null) {
// Restore value of members from saved state
rm_1ts = savedInstanceState.getString("arm_1");
rm_2ts = savedInstanceState.getString("arm_2");
rm_1.setText(rm_1ts);
rm_2.setText(rm_2ts);
}
Button bton = (Button)findViewById(R.id.ajoutUn);
bton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
rm_1ts = rm_1.getText().toString();
rm_2ts = rm_2.getText().toString();
ajouter(v);
}
});
The problem is that onSaveInstanceState is only called when your Activity is killed via System to free memory or a 3rd party app. But when you press a back button in an Activity it simply is equivalent to finish(). In this case onSaveInstanceState is not called. So if you want to store data every time your Activity is created just store the values in a SharedPreference. You can store the values either in onStop or onPause method depending on your needs.
Here you can learn more about SharedPrefence and other types of storage options.
For the sake of simplicity, you could store the value in the SharedPreferences.
getSharedPreferences().edit().putString("myEditText", yourValue).commit();
That's it.
Try restoring the state in onStart or onResume instead of onCreate. onCreate is only called if the activity needs to be recreated after it is destroyed. Often the activity will be retained in the background in a stopped state, and won't call onCreate when it comes back.
Anywhere in your file, put:
#Override
public void onResume() {
super.onResume();
//Your code here
}
Here is my GamePlay Activity code
public class GamePlay extends Activity implements OnClickListener {
private boolean disableSound = false;
//.....
//Code Code
//.....
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//.....
//Code Code
//.....
}
#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("disableSound", disableSound);
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore UI state from the savedInstanceState.
// This bundle has also been passed to onCreate.
disableSound = savedInstanceState.getBoolean("disableSound");
Menu menu = (Menu)findViewById(R.menu.tic_tac_toe);
MenuItem toggleSoundItemMenu = menu.findItem(R.id.toogle_sound_menu);
if(disableSound)
toggleSoundItemMenu.setTitle(R.string.toggle_sound_off_label);
else
toggleSoundItemMenu.setTitle(R.string.toggle_sound_on_label);
}
//other functions and code
}
Now on game restart I am restarting the activity. Following code is inside the onClickListener() withing appropriate case
case R.id.game_play_restart_button:
Intent restartActivity = new Intent(this,GamePlay.class);
finish();
startActivity(restartActivity);
break;
But still the state does not persist. I disable the sound and restart the game then sound turns back on which is the default behavior. What am I missing? Any suggestion is appreciated.
The savedInstanceState bundle is kept by the system as long as the activity hasn't been destroyed by the system.
When you call finish, you destroy the current activity, and the bundle that comes with it.
That's the reason why you can't get your boolean back.
You should consider passing this boolean as an extra in the intent like:
restartActivity.putExtra("disableSound", disableSound)
And then on the onCreate of your activity:
getIntent().getBooleanExtra("disableSound", false)
Please note that the last parameter false is just a default value. You can set it to true if that's the behaviour you want.