I have a button that increase a variable by one and the result is printed in a TextView. When I rotate the device the variable value is maintained, but if I exit the activity and then re-enter, every value is reset. How can I fix this?
int n=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.prova);
final TextView tv = (TextView)findViewById(R.id.tvProva);
Button b = (Button)findViewById(R.id.bProva);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
n++;
tv.setText(""+n);
}
});
if(savedInstanceState!=null){
n = savedInstanceState.getInt("n");
tv.setText(""+n);
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("n", n);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
savedInstanceState.getInt("n");
}
There are a couple of potential options.
SharedPreferences, as Tejas said, below is an example of how you might use this;
SharedPreferences pref = getApplicationContext().getSharedPreferences("MyPref", 0);
To save you value;
Editor editor = pref.edit();
editor.putInt("n", n);
editor.apply();
To retrieve your value;
pref.getInt("n", 0);
The above was taken from a previous post; https://stackoverflow.com/a/24099496/4644276
Alternatively you could leverage the Repository pattern. A repository in simplest terms is an object that can persist for the life of the application, therefore it can persist across different activities. It cannot however survive killing the application unless you leverage SharePreferences as previously discussed or using an API or local database.
If you'd like to look in to the repository pattern further than it is discussed in the Guide to app architecture page on the Android Developer portal.
https://developer.android.com/jetpack/docs/guide
Related
I have a page in my application where the user can enter a product name and it's calorie count, which it then removes from a daily calorie count which comes from another class. This works perfectly I wanted to make it so that it doesn't reset to the original value each time the page is opened (unless its a fresh install / manual reset via a button).
I came across SharedPreferences and tried to implement this, but it always comes up with the default value in my onResume method and I am not too sure why and need some assistance to figure out what I am doing wrong and how to fix it, as I will need to use this in several other classes also.
My Class:
public class CalorieTracker extends AppCompatActivity {
protected String age, calorieCount;
protected EditText itemName, kCal;
protected TextView remainingCalories;
protected Button submitBtn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_calorie_tracker);
getSupportActionBar().setDisplayShowHomeEnabled(true);
Bundle extras = getIntent().getExtras();
age = extras.getString("age");
calorieCount = extras.getString("calories");
System.out.println(age + ":" + calorieCount);
itemName = findViewById(R.id.productNameCalorieTracker);
kCal = findViewById(R.id.calorie_kcal);
submitBtn = findViewById(R.id.submit_calorie);
remainingCalories = findViewById(R.id.remainingCalorieCount);
remainingCalories.setText(calorieCount);
submitBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int currentCount = Integer.parseInt(remainingCalories.getText().toString());
int enteredAmount = Integer.parseInt(kCal.getText().toString());
calorieCount = String.valueOf(currentCount - enteredAmount);
remainingCalories.setText(calorieCount);
SharedPreferences mPrefs = getPreferences(MODE_PRIVATE);
SharedPreferences.Editor editor = mPrefs.edit();
editor.putString("sessionCalories",remainingCalories.getText().toString());
editor.commit();
}
});
}
#Override
protected void onResume() {
super.onResume();
SharedPreferences mPrefs = getPreferences(MODE_PRIVATE);
remainingCalories.setText(mPrefs.getString("sessionCalories",""));
}
}
http://prntscr.com/me99dp
Image of what it looks like when I boot the application, even though the initial calorieCount value should be 2100 which I get from the previous page using the Bundle extras.
If I change the
line remainingCalories.setText(mPrefs.getString("sessionCalories","")); in my onResume method, to :
remainingCalories.setText(mPrefs.getString("sessionCalories","3")); then it shows 3 initially.
Make sure that your data is updated in shared preference correctly. In Activity life cycle after onviewCreated only onResume called .
so if your current activity will go to foreground or rotate then only onResume will call again.
so solution ,in button click after set the value and get value from sharedpreference and display like this
submitBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// first time save data
setvalueFromSharedpreference()
}
});
public setvalueFromSharedpreference()
{
SharedPreferences mPrefs = getPreferences(MODE_PRIVATE);
remainingCalories.setText(mPrefs.getString("sessionCalories",""));
}
when I boot the application, even though the initial calorieCount
value should be 2100 which I get from the previous page using the
Bundle extras.
If I change the line
remainingCalories.setText(mPrefs.getString("sessionCalories","")); in
my onResume method, to :
remainingCalories.setText(mPrefs.getString("sessionCalories","3"));
then it shows 3 initially.
Reason editText remainingCalories always have default (sharedpreference value) is because onResume method is called after onCreate in activity's lifecycle. Thats why, Bundle extras value is being overwritten by sharedpreference value.
You can achieve this in onCreate method by checking if Intent extras has value. If yes, then set that value otherwise set the sharedPrefrence's value as follows
#Override
protected void onCreate(Bundle savedInstanceState) {
...
SharedPreferences mPrefs = getPreferences(MODE_PRIVATE);
calorieCount = mPrefs.getString("sessionCalories","");
Bundle extras = getIntent().getExtras();
age = extras.getString("age");
if(!calorieCount.isEmpty)
remainingCalories.setText(calorieCount);
else
{
calorieCount = extras.getString("calories");
}
System.out.println(age + ":" + calorieCount);
itemName = findViewById(R.id.productNameCalorieTracker);
kCal = findViewById(R.id.calorie_kcal);
submitBtn = findViewById(R.id.submit_calorie);
remainingCalories = findViewById(R.id.remainingCalorieCount);
remainingCalories.setText(calorieCount);
}
And remove the sharedPreference setting from onResume.
Hope it helps cheers:)
I'm trying to save a TextView value that changes on a button click and keep it stored until I kill the app.
I am trying to use onSaveInstanceState and onRestoreInstanceState to save and restore as long as the app is running. It doesn't work for me. Here is my code.
TextView questionText;
Button button ;
String perso1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
perso1 = MainActivity.perso;
questionText = (TextView)findViewById(R.id.perso);
questionText.setText(perso1));
getSupportActionBar().setIcon(R.drawable.ic_back_icon);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(R.string.settings);
button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
resetConsent();
questionText.setText("You clicked on the button");
}
});
}
#Override
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);
String newtext = questionText.getText().toString();
outState.putString("TEXT", newtext);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onRestoreInstanceState(savedInstanceState);
questionText.setText(savedInstanceState.getString("TEXT"));
}
I'm trying to keep the new value of textview when I click on the button until I kill the app. What am I doing wrong?
ViewModel is what you need!
Why
The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.
It makes your life easier. You don't need to think on how to save it in youe savedInstanceState, but you can just store the String in your ViewModel (as a LiveData), then observe it.
With LiveData, you can change the value everytime the button clicked, and observe the value everytime it changes.
You can always try to save state in a different way.
#Override
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);
String newtext = questionText.getText().toString();
outState.putString("TEXT", newtext);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
//check if there was a previous saved state
if(savedInstanceState != null){
//get the value you stored earlier in onSaveInstanceState()
perso1 = savedInstanceState.getString("TEXT");
}
questionText = (TextView)findViewById(R.id.perso);
questionText.setText(perso1));
//....
}
But this is just another way to save state.
I think i your error is explained below.
//you did this correctly- look, you set questionText here
onRestoreInstanceState(Bundle savedInstanceState){
super.onRestoreInstanceState(savedInstanceState);
//set the questionText below
questionText.setText(savedInstanceState.getString("TEXT"));
}
but then in onCreate() you set the questionText again. This time to an incorrect value.
perso1 = MainActivity.perso;//< -- setting perso1 to nothing?
questionText = (TextView)findViewById(R.id.perso);
questionText.setText(perso1));//<-- setting questionText again
onRestoreInstanceState
This method is called between onStart() and onPostCreate(Bundle).
In onSaveInstanceState() you did it correctly, in onRestoreInstanceState() you did it correctly, in onCreate() you set the value again to the wrong value.
Additionally read this when deciding to keep saving state this way or using a ViewModel
For simple data, the activity can use the onSaveInstanceState() method and restore its data from the bundle in onCreate(), but this approach is only suitable for small amounts of data that can be serialized then deserialized, not for potentially large amounts of data like a list of users or bitmaps.
i have been through this documentation regarding the topic save a state before the foreground activity will be destroyed...
and everything works really good now (after a device rotation), but when i rotate my device again after a rotation, i will loose my data again :(
here is my code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MainActivity activity = this;
activity.setTitle("Cow Counter");
TextView QntyResultField = findViewById(R.id.textView);
QntyResultField.setText(Integer.toString(cowQnty));
}
// invoked when the activity may be temporarily destroyed, save the instance state here
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("qnty", cowQnty);
}
// How we retrieve the data after app crash...
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
//cowQnty = savedInstanceState.getInt("qnty");
TextView QntyResultField = findViewById(R.id.textView);
QntyResultField.setText("Cows: "+Integer.toString(savedInstanceState.getInt("qnty")));
}
I think the solution will be maybe to implement a check if an instance state was already restored before...
i have tried then this here:
if(savedInstanceState.getInt("qnty") != 0){
TextView QntyResultField = findViewById(R.id.textView);
QntyResultField.setText("Cows: "+Integer.toString(savedInstanceState.getInt("qnty")));
}
buit then my inital part in my onCreate() method will write a zero in my result field
TextView QntyResultField = findViewById(R.id.textView);
QntyResultField.setText(Integer.toString(cowQnty));
Could anyone tell me if I am close to the solution?
You use a variable called cowQnty to store the value that is then saved in the bundle for your onSaveInstanceState as outState.putInt("qnty", cowQnty);, then when you restore it in onRestoreInstanceState you only set the TextView's value to the retrieved value and do not update the value for cowQnty.
How do you expect then to save an empty field again? There are two solutions to this;
Firstly, if cowQnty is not a sizeable amount and you do not mind using a tad of RAM, make cowQnty a static field and it will persist the data without needing to save it in a Bundle at all.
Secondly, just set cowQnty's value once again when you restore your state (why did you comment it out??), like so:
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
cowQnty = savedInstanceState.getInt("qnty");
TextView QntyResultField = findViewById(R.id.textView);
QntyResultField.setText("Cows: "+Integer.toString(savedInstanceState.getInt("qnty")));
}
I am implementing the Settings for my android app through the PreferenceFragment.
My android:summary for the different Preferences should display the current value at all times therefore I have read through severals posts and the official documentation.
Although I got it working technically my solution seems kind of hacky and I am now searching for best practice since I found no good source on how it is meant to be properly implemented.
For example I implemented onSharedPreferenceChanged to listen for changes and to update the UI, but after every restart of the PreferenceFragment, the initial android:summary is shown again. To solve this I added this to the onCreate
// display current value in the UI
EditTextPreference editText = (EditTextPreference) findPreference("serverAddress");
editText.setSummary(editText.getText());
Is this is how it is supposed to be done or am I misunderstanding something ?
Full Code:
public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
public static final String KEY_PREF_SERVER_ADDRESS = "serverAddress";
public static final String KEY_PREF_GENDER = "gender";
public SettingsFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
//Load the preferences from the XML file
addPreferencesFromResource(R.xml.preferences);
// display current value in the UI
EditTextPreference editText = (EditTextPreference) findPreference("serverAddress");
editText.setSummary(editText.getText());
}
// Listen for settings changes and update the UI
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(KEY_PREF_SERVER_ADDRESS)) {
Preference serverAddressPref = findPreference(key);
//Set UI to display updated summary
serverAddressPref.setSummary(sharedPreferences.getString(key, ""));
}
if (key.equals(KEY_PREF_GENDER)) {
Preference serverAddressPref = findPreference(key);
//Set UI to display updated summary
serverAddressPref.setSummary(sharedPreferences.getString(key, ""));
}
}
#Override
public void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
}
}
My question is "Is there any way to save state of activity, that can be used when application has been restart.".
In my application, I had been override onSaveInstanceState and onRestoreInstanceState to save and restore my instance state.
I also used SharedPreferences to save the state. But I found that SharedPreference has been clear when I pressed Back Buttaon and restart my application.
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
SharedPreferences pref = getSharedPreferences(MY_APP, MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.putString(USER_NAME, name.getText().toString());
editor.putInt(COUNT_STATE, count);
editor.commit();
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
SharedPreferences pref = getSharedPreferences(MY_APP, MODE_PRIVATE);
name.setText(pref.getString(USER_NAME, ""));
count = pref.getInt(COUNT_STATE, 0);
}
I also know that this problem has been solved if I used external or local storage.
I want to know that can I persist application state without using file or database.
at onBackPressed() you need to store your state
and when activity created onCreate() you need to restore it
private void saveMyState(){
SharedPreferences pref = getSharedPreferences(MY_APP, MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.putString(USER_NAME, name.getText().toString());
editor.putInt(COUNT_STATE, count);
editor.commit();
}
private restoreMyState(){
SharedPreferences pref = getSharedPreferences(MY_APP, MODE_PRIVATE);
name.setText(pref.getString(USER_NAME, ""));
count = pref.getInt(COUNT_STATE, 0);
}
#Override
public void onBackPressed() {
saveMyState();
super.onBackPressed();
}
#Override
public void onCreate(Bundle savedInstanceState){
//init views, buttons, textViews (findViewById)...
//do other works ...
//:
//:
//then try to restore state (if saved)
restoreMyState();
}
if you want you can do the same call saveMyState() and restoreMyState() at
onSaveInstanceState() and onRestoreInstanceState() in case of orientation changed
i think this will cover all the cases you want.
PS: using SharedPreferences will write/read to a file, under the hood so you are already using file if you are using SharedPreferences
For my question, I try to change behavior of Pressed Back Button by overring onBackPressed.
In this method I write moveToBackTask(true).
#Override
public void onBackPressed() {
moveTaskToBack(true);
}
My application state has been restored when I pressed back button and restart application.
But I think that this state can't be restored when I restart my device.
Do I need to store my state in a file?