setSingleChoiceItems value doesn't stick after Activity kill - java

Hello guys and Happy new year to all!
I'm having a weird trouble in my app which I can't seem to fix. It should be a logic error, but I'm not able to somehow catch it.
Here is my code
public String[] str={"Disabled","Sound Quality Prefered","Bass Prefered","Battery Prefered",};
public int ThemePresetValue = 0;
private int SelectedThemePresetValue = 0;
public void presets() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
alertDialog.setTitle("Select Your Sound Preset");
alertDialog.setNegativeButton("Cancel", null);
alertDialog.setPositiveButton("Select", themePresetDialogPositiveListener);
alertDialog.setSingleChoiceItems(str, ThemePresetValue, PresetListListener);
alertDialog.show();}
DialogInterface.OnClickListener PresetListListener =
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
SelectedThemePresetValue = which;
}
};
DialogInterface.OnClickListener themePresetDialogPositiveListener =
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
mPreset = "";
ThemePresetValue = SelectedThemePresetValue;
if (ThemePresetValue == 0) {
mPreset = "Disabled";
} else if (ThemePresetValue == 1) {
mPreset = "Sound Quality Prefered";
} else if (ThemePresetValue == 2) {
mPreset = "Bass Prefered";
} else if (ThemePresetValue == 3) {
mPreset = "Battery Prefered";
}
if (mPreset.equals("Disabled")) {
disabler();
} else if (mPreset.equals("Sound Quality Prefered")) {
SoundQPreset();
} else if (mPreset.equals("Bass Prefered")) {
bassPreset();
} else if (mPreset.equals("Battery Prefered")) {
batteryPreset();
}
}
};
The problem is that after I choose one of the presets the choice sticks until the app is closed from multitasking (MainActivity gets restarted or killed). Then if I re-open the app, the choice of dialog is re-set onto 0 ("Disabled").
Why is this happening? Do you have a solution?

Yes, the field is created each time anew for the respective object and since this object (i.e. the activity) is destroyed the memory holding the field is freed up as well. So the field's lifespan is bounded by that of the object. To make it continuous, you better save the value in SharedPreferences, or in general to write it out to some storage, before destroying the activity, e.g. in onPause() and then fetch it from those preferences in onCreate() or onResume() callbacks. For example:
/*--- Saving ---*/
SharedPreferences prefs =
getApplicationContext().getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
prefs.edit().putInt(KEY_NAME, VALUE).apply();
/*--- Retrieving ---*/
int oldValue =
getApplicationContext().getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE)
.getInt(KEY_NAME, 0);
PREFERENCES_NAME is the file name of your shared preferences file. KEY_NAME is the key, under which you save and later retrieve the stored value. VALUE is simply the value to save.
Hope this helps!

As you are not persisting the user's choice, the choice remains in memory until activity finishes. You should save the user's choice locally using SharedPreferences or sqlite for instance!
When the activity restarts you can read the saved value and set the option as selected!

Related

how to save state of my button with share preferences?

In my application when user click back , I make an alert dialog that included 2 buttons. first button is Exit that allow user to exit the application.
the second button is 5 star that allow user to rate me in the market.
it works correctly.
but the problem is that when I kill the application and I run it again, this process repeat. and I want if the user rate me before , I don't show the 5 star button to user again.
how can I save my state button in it?
I know that I must share preferences , but how?
int star = 0;
public void onClick(View v) {
int id = v.getId();
if(id == R.id.button1 && stringListCounter <lines.size() - 1) {
stringListCounter++;
} else if (id == R.id.button2 && stringListCounter > 0) {
stringListCounter--;
}
txtQuestion.setText(lines.get(stringListCounter));
}
public void onBackPressed() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(QuizActivity.this);
alertDialog.setTitle("please rate us");
alertDialog.setPositiveButton("5star", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent browserIntent = new Intent(
Intent.ACTION_EDIT,
Uri.parse("http://cafebazaar.ir/app/my package name/?l=fa"));
startActivity(browserIntent);
star ++;
}
});
alertDialog.setNegativeButton("exit", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent intent1 = new Intent(Intent.ACTION_MAIN);
intent1.addCategory(Intent.CATEGORY_HOME);
intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent1);
}
});
alertDialog.show();
}
here my star value is 0. when user rate me , the value of star become 1 . I
want save the my star value to 1 that this process don't repeat again.
please help
First Of Save Preferences
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt("KeyValue", newHighScore);
editor.commit();
Read from Shared Preferences
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
int defaultValue = getResources().getInteger("KeyValue");
after get preference easily check condition
you can create one method in shared preferences that will give your app state means when user is clicking on 5 start on that time you have to set the app state 1. and next time before calling this
alertDialog.setPositiveButton("5star", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent browserIntent = new Intent(
Intent.ACTION_EDIT,
Uri.parse("http://cafebazaar.ir/app/my package name/?l=fa"));
startActivity(browserIntent);
star ++;
}
});
apply if condition and check the state of the app in shared preference means if state is 1 then don't allow to execute this functionality else allow.

How to store and retrieve what was selected from a single choice item

I have the following code:
protected void showSelectToDialog() {
boolean[] checkedDate = new boolean[toDate.length];
int count = toDate.length;
DialogInterface.OnClickListener setD2 = new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
//TODO Auto-generated method stub
onChangeSelectedTo(which);
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Select To Year");
builder.setSingleChoiceItems(toDate, count, setD2);
builder.setCancelable(true);
builder.setPositiveButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
dialog2 = builder.create();
dialog2.show();
}
protected void onChangeSelectedTo(int j) {
bTo.setText(toDate[j]);
sTo = ((AlertDialog)dialog2).getListView().getCheckedItemPosition();
blTo = true;
displayToast(String.valueOf(sTo));
to = j;
dialog2.dismiss();
}
What I am looking to do is, when the dialog loads the first time and the user selects a choice it is stored. So the next time the user opens the dialog, it will remember what was select and scroll to that choice.
How do I accomplish that?
Save the selected choice's position for the first time using Shared Preferences.
Then at the start of showSelectToDialog() check if any value exists in Shared Preferences, if so, then set the value of count from the Shared Preferences else set value of count to toDate.length.
I can't see the rest of your code, but all you have to do is save the user's choice in a variable somewhere else, and then read that choice every time you open the dialogue. It could be a static variable on the class, or it could be an instance variable of the class, or it could be a public field of some other class you have access to, like a parent object. You just need to assign it when you close the dialogue, and read it back and initialize the value to what you read when you open the dialogue.

Does this snippet cause an infinite loop or other?

Only on old android devices (2.x) I've a crash caused by stackoverflow everytime I rotate emulator. If I comment "preferenze()" emulator does not crash but app does not keep new settings. Can this code create an infinite loop? Is a incorrect code? What should be to runs correctly? Thanks!
private boolean preferencesChanged;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
private void preferenze() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
CheckboxPreference = prefs.getBoolean("checkboxPref", true);
ListPreference = prefs.getString("listpref", "");
numeronotifiche = prefs.getString("notify", "");
Sound = prefs.getString("sound", "");
barranotifiche = prefs.getBoolean("keep", false);
natura = prefs.getBoolean("suoninaturasino", false);
snatura = prefs.getString("suoninaturascelta", "");
snaturaold = prefs.getString("snaturaoldvalue", "");
if (snaturaold != snatura){
stopService(new Intent(this, UnUsedService.class));
}
SharedPreferences prefs2 = getSharedPreferences(PRIVATE_PREF, 0);
Editor editor10 = prefs2.edit();
editor10.putString("snaturaoldvalue", snatura);
editor10.commit();
// suoni attivati (o no)
if (natura){
startService(new Intent(this, UnUsedService.class));
}
else {
stopService(new Intent(this, UnUsedService.class));
}
if (barranotifiche){
showNotification();
}
else {
cancelNotification();
}
GestioneAllarme alarm = new GestioneAllarme();
if (CheckboxPreference){
if (numeronotifiche.equals("3")){
alarm.CancelAlarm(this);
alarm.SetAlarm3(this);
}
else if (numeronotifiche.equals("1")){
alarm.CancelAlarm(this);
alarm.SetAlarm1(this);
}
else if (numeronotifiche.equals("2")){
alarm.CancelAlarm(this);
alarm.SetAlarm2(this);
}
else {
//
}
}
else {
//
GestioneAllarme alarm2 = new GestioneAllarme();
alarm2.CancelAlarm(this);
}
//
if (Sound.equals("")){
Sound = "2";
Editor editor = prefs.edit();
editor.putString("sound", "2");
editor.commit();
}
if (ListPreference.equals("")){
ListPreference = "1500";
Editor editor = prefs.edit();
editor.putString("listpref", "1500");
editor.putInt("indexfade", 1500);
editor.commit();
}
if (numeronotifiche.equals("")){
numeronotifiche = "2";
Editor editor = prefs.edit();
editor.putString("numeronotifiche", "2");
editor.commit();
}
fade = Integer.parseInt(ListPreference);
notify = Integer.parseInt(numeronotifiche);
if (fade == 500){
animazione = R.style.MyCustomTheme1;
fadein = R.anim.fadein500;
fadeout = R.anim.fadeout500;
}
else if (fade == 1000){
animazione = R.style.MyCustomTheme2;
fadein = R.anim.fadein1000;
fadeout = R.anim.fadeout1000;
}
else if (fade == 1500){
animazione = R.style.MyCustomTheme3;
fadein = R.anim.fadein1500;
fadeout = R.anim.fadeout1500;
}
else if (fade == 2000){
animazione = R.style.MyCustomTheme4;
fadein = R.anim.fadein2000;
fadeout = R.anim.fadeout2000;
#Override
protected void onResume() {
super.onResume();
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
preferencesChanged = true;
}
};
sp.registerOnSharedPreferenceChangeListener(listener);
protected void onStop(){
super.onStop();
if(preferencesChanged){
//Update the app
preferenze();
}
}
public class Preferences extends PreferenceActivity implements OnSharedPreferenceChangeListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.layout.preferences);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String listpref) {
It seems that as soon as preferenze() always modify the shared preferences you will have an infinite loop.
Since you didn't post the complete code it's difficult to say. But I guess that your code is such that it always modify prefs only on android 2.x
you can try something like this to avoid infinite loop.
private boolean isPreferenzeRunning = false;
...
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String listpref) {
if(!isPreferenzeRunning)preferenze();
}
};
...
private void preferenze()
isPreferenzeRunning = true;
try{
...
}finally{isPreferenzeRunning = false;}
}
That code wouldn't even compile.
The code in preferenze() will return the preference values (boolean, String, int, etc), not the Preference objects. By changing the values in that method, you will also cause a StackOverflowError.
What is the need for a OnSharedPreferenceChangeListener?
// here several if/if else to change value
Those sentences probably change the Shared Preferences, that in turn will fire your listener, which in turn will call preferenze, ..., and so on. If this continues for ever, a S.O will be thrown. Now depending on the conditions it could happen that the preferenze method only reads but does not modify anything. In this case the loop will end.
And about the error being observed in 2.X devices only, it could be due to 4.x devices being more recent and probably having more RAM memory.
UPDATE:
The code is still incomplete. Looks like there are two activities: the one you posted first and the new one. I guess (that's all I can do with the code you posted) you have a PreferenceActivity to show the settings and allow the user to change them, and the listener is there to update other parts of the application according to the new settings. The problem is that when the listener is called, it itself modifies the settings, and this in turn will call the listener again, which will modify the preferences again, and so on. This will throw an SOException once the heap runs out of memory.
A way of rearranging the code to solve this would be:
Register the OnSharedPreferenceChangeListener in your activity's onResume instead of onCreate, and deregister it in the onPause method (calling unregisterOnSharedPreferenceChangeListener). Deregistering is very important because we don't want to listen for changes once the user leaves the screen, or the activity is recreated by the system (for instance when the device rotates):
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//We have removed the listener registration from here
}
#Override
protected void onResume() {
super.onResume();
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String listpref) {
//I'll show what to do here in point 2.
}
};
sp.registerOnSharedPreferenceChangeListener(listener);
}
#Override
protected void onPause() {
super.onPause();
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
sp.unregisterOnSharedPreferenceChangeListener(listener);
}
With your current code, each time the user changes a single setting, the preferenze method is called to update the app. So if it changes 5 fields, the method is called 5 times. What we could do now is to check for changes just once. I assume you don't care how many fields the user has changed, since all you need is to know if there are changes or not. So in the listener, instead of calling preferenze, you could set a boolean flag to true:
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
preferencesChanged = true;
}
Ok, so now we have a way of telling whether the settings have changed or not. When the user is done and the activity is about to be closed, the methods onPause, onStop and onDestroy will be called in this order. You can use one of these methods to check the boolean flag and only if there are changes, update the app. This way, if the user changes 1, 3 or 20 fields, we will update the app just once at the end. You can do this in any of the 3 thethods, but it's very important to do this AFTER deregistering the listener (onPause), or else you'll run into problems again. Example:
protected void onStop(){
super.onStop();
...
if(preferencesChanged){
//Update the app
preferenze();
}
}
You might need to change some things but overall you get the idea.

How to get most recent sharedPreferences

I have a background service that reads cpu usage and frequency and displays it on notification bar
In application settings(Preferences) i have a option to chose to display only frequency only load or both
But method for getting shared preferences wont get most recent SharedPreference
it get SharedPreference only first time service starts and if i chose diferent option in Preference screen it wont update in service
Here is the code
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Runnable runnable = new Runnable() {#Override
public void run() {
while (thread) {
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
items = sharedPrefs.getString("notif", "freq");
System.out.println(items); //this keeps displaying the same value even if i go to Preference screen and change to something else
if (items.equals("freq") || items.equals("both")) {
}
if (items.equals("load") || items.equals("both")) {
} //reading frequency and load depending on what is selected
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mHandler.post(new Runnable() {#Override
public void run() {
if (thread) {
createNotification(); //create notification
}
}
});
}
}
};
new Thread(runnable).start();
return START_STICKY;
}
SOLVED
Because my service was running in separate process i had to add this flag when accesing shared preference
private final static int PREFERENCES_MODE = Context.MODE_MULTI_PROCESS;
and change like this
sharedPrefs = this.getSharedPreferences("preference name", PREFERENCES_MODE);
Ensure you write your data to shared preferences correctly, specifically you commit() your changes, as docs say:
All changes you make in an editor are batched, and not copied back to
the original SharedPreferences until you call commit() or apply()
Here is example code:
SharedPreferences.Editor editor = mPrefs.edit();
editor.putBoolean( key, value );
editor.commit();
I think the error is on the line
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
where you are passing 'this' from inside a thread? Can you change it with the application context?

Java /Android Dialog with EditText - Boolean check on strings

I have a boolean method returning true or false to check whether or not data exists inside of strings. Everything works ok if the user enters all data or does not run through the dialogs.....BUT....if the user DOES NOT enter data in the "getItemsEditText" dialog popup AND still clicks "OK", this boolean is resolving to true, even though "pricePerItemText" still has nothing stored. This is the boolean method:
public Boolean doesAllDataExistCheckBool ()
{
if (pricePerItemText != "" && itemsPerDayText != "" && sleepTimeText != "" &&
wakeTimeText != "")
{
SharedPreferences.Editor editor = mySharedPreferences.edit
(); //opens shared preference editor
editor.putBoolean("storedDoesAllDataExist", true);
editor.commit(); //commit changes to mySharedPreferences
//End storing shared preferences
return true;
}
else
{
SharedPreferences.Editor editor = mySharedPreferences.edit
(); //opens shared preference editor
editor.putBoolean("storedDoesAllDataExist", false);
editor.commit(); //commit changes to mySharedPreferences
//End storing shared preferences
return false;
}
}
Here is where the boolean is being tested to see if true or false:
if (position == 4)
{
allDataExists = doesAllDataExistCheckBool (); //checks if true or false
if (serviceStarted == true)
{
Context context = getApplicationContext();
String text = "Schedule is already running";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
if (serviceStarted == false && doesAllDataExistCheckBool () == true)
{
startScheduleService();
}
if (serviceStarted == false && doesAllDataExistCheckBool () == false)
{
Context context = getApplicationContext();
String text = "Please enter all data before starting!";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
}
Here is how the dialog with EditText and OK/Cancel buttons is written:
case ITEMS_PER_DAY :
LayoutInflater li = LayoutInflater.from(this);
final View itemsEntryView = li.inflate(R.layout.settings_dialog_input, (ViewGroup)
findViewById(R.id.layout_root));
final EditText getItemsEditText = (EditText)itemsEntryView.findViewById
(R.id.DialogEditText);
return new AlertDialog.Builder(SettingsActivity.this)
.setTitle("This is the title")
.setView(itemsEntryView)
.setPositiveButton("Ok", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int whichButton)
{
itemsPerDayText = getItemsEditText.getText().toString(); //gets input from
edittext and saves it to a string itemsPerDayText
//Initialize shared preferences
SharedPreferences.Editor editor = mySharedPreferences.edit(); //opens editor
editor.putString("storedItemsPerDayText", itemsPerDayText);
editor.commit(); //commit changes to mySharedPreferences
//End storing shared preferences
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int whichButton)
{
//user click cancel
}
}).create();
Is there another way to do this? Why can the user still click "OK" if they did not enter anything at all? Any ideas? Thanks guys!
You posted way too much code. But right away I noticed this
pricePerItemText != ""
Assuming pricePerItemText is a string, which we really have no idea since you didn't include that, that's not how you compare strings in java. It needs to be
!pricePerItemText.equals("");
Edit:
In java, the == operator compares objects references, not values. So
String mytext = "text";
if (mytext == "text"){ print "True"}
will never print true because the mytext variable is pointing to some memory location, which is most definitely not the same as where "text" points to.
The fact that
"text == "text"
is true is a an artifact of Java keeping a string pool so it doesn't have to reallocate new strings. This is a major cause of confusion.
Here's a random link which describes it probably better
http://leepoint.net/notes-java/data/expressions/22compareobjects.html

Categories