I've really been struggling through this. New to Java/Android. I'm writing my first app and this is the first thing that has taken me longer than a couple days of searching to figure out. Here's the setup: It's a BAC calculator / drink counter:
A formula is used to calculate the BAC. Here's the forumla:
Bac = ((StandardDrinks / 2) * (GenderConstant / Weight)) - (0.017 * Hours);
So as you can see, being able to modify the gender and weight will produce more accurate and personalized results. So I have them as doubles:
double GenderConstant = 7.5; //9 for female
double Weight = 180;
To change these variables I would like the person to be able to go into the settings and choose different values. I have these things set up, but not linked to the variables shown above because I cannot for the life of me figure out how. Here they are:
I press the menu button and this pops up. Great. I'll click Settings.
Now the preferences pops up. Here is my preferences.xml:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="Personal Settings">
<ListPreference
android:title="Gender"
android:summary="Verify or deny the presence of a Y chromosome."
android:key="genderPref"
android:defaultValue="male"
android:entries="#array/genderArray"
android:entryValues="#array/genderValues" />
<ListPreference
android:title="Weight"
android:summary="How much the planet pulls on you, in pounds."
android:key="weightPref"
android:defaultValue="180"
android:entries="#array/weightArray"
android:entryValues="#array/weightValues" />
</PreferenceCategory>
<PreferenceCategory android:title="Drink Settings">
<ListPreference
android:title="Beer Size"
android:summary="The volume of your beer, in ounces."
android:key="beerPref"
android:defaultValue="12"
android:entries="#array/beerArray"
android:entryValues="#array/beerValues" />
<ListPreference
android:title="Shot Size"
android:summary="The volume of your shot, in ounces."
android:key="shotPref"
android:defaultValue="1.5"
android:entries="#array/shotArray"
android:entryValues="#array/shotValues" />
<ListPreference
android:title="Wine Size"
android:summary="The volume of your wine, in ounces."
android:key="winePref"
android:defaultValue="5"
android:entries="#array/wineArray"
android:entryValues="#array/wineValues" />
</PreferenceCategory>
</PreferenceScreen>
Onward to the weight ListPreference:
And that shows up. The values are stored as string-arrays in res/values/arrays.xml. Here's a sample, of just the weight ones:
<string-array name="weightArray">
<item>120 lbs</item>
<item>150 lbs</item>
<item>180 lbs</item>
<item>210 lbs</item>
<item>240 lbs</item>
<item>270 lbs</item>
</string-array>
<string-array name="weightValues">
<item>120</item>
<item>150</item>
<item>180</item>
<item>210</item>
<item>240</item>
<item>270</item>
</string-array>
This is basically as far as I've gotten. I can click a value, sure, but it doesn't change the formula because it's not linked with the doubles I created in DrinkingBuddy.java. All of the stuff displayed in the settings are just empty shells for now, including the spinner on the main layout (the default time is just set to 1 hour)
I did create a Preferences.java and have tried implementing various combinations of code found in tutorials and resources around the web, but to no avail. Here it is anyway, filled with failed attempts to make beerPref (the settings option to change how many ounces in the beer) correlate with a variable in my main class:
package com.dantoth.drinkingbuddy;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.Preference.OnPreferenceClickListener;
public class Preferences extends PreferenceActivity {
public static final String PREF_BEER_SIZE = "PREF_BEER_SIZE";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
//Get the custom preference
Preference beerPref = (Preference) findPreference("beerPref");
beerPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
SharedPreferences customSharedPreference = getSharedPreferences("myCustomSharedPrefs", Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = customSharedPreference.edit();
editor.commit();
return true;
}}
);}
}
A full on tutorial and sample code would be AWESOME as I've yet to find any reliable guides out there.
I'm still working all this out myself, but (somewhat adapted from my version) I think your Preferences class only needs to do the following:
public class Preferences extends PreferenceActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// load the XML preferences file
addPreferencesFromResource(R.xml.preferences);
}
}
Then in your main class, you can refer to the preferences:
public class DrinkingBuddy extends Activity
implements OnSharedPreferenceChangeListener {
private int weight;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
// register preference change listener
prefs.registerOnSharedPreferenceChangeListener(this);
// and set remembered preferences
weight = Integer.parseInt((prefs.getString("weightPref", "120")));
// etc
}
// handle updates to preferences
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.equals("weightValues")) {
weight = Integer.parseInt((prefs.getString("weightPref", "120")));
}
// etc
}
}
The saving of preference updates is handled for you.
(Not too sure about public/private declarations!)
You are requesting probably two different set of preference files.
Make sure you store the ListPreference values in the same files.
Start up adb roll to the cd /data/data/com.your.package and look for folders and files of type preferences.
I think the bug is that you specify a different file than the one the setting has been saved too:
Try changing this:
SharedPreferences preferences = getSharedPreferences(PREF_FILE_NAME, MODE_PRIVATE);
to
SharedPreferences preferences = PreferenceManager
.getDefaultSharedPreferences(context);
Then you will probably have to query only
preferences.getString('weightPref', null);
Also you do not need the Editor. The preferences are saved automatically.
For most apps, it is most convinient to use the default shared preferences. You can get from anywhere in you app them with:
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
You can save new variables into it with:
sp.edit().putString("var_name", "var value".apply();
Related
I want to create a settings class one. I've created one myself right now. For example, I created a key switch called camera. This clicklistener how do I do this?
SettingsActivity Class:
public class SettingsActivity extends PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit();
}
public static class MyPreferenceFragment extends PreferenceFragment
{
#Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
}
}
}
Settings Activity XML:
<androidx.preference.PreferenceCategory
android:key="the_key_to_retrieve_the_preference_in_code">
<androidx.preference.SwitchPreference
android:key="camera"
android:summary="...."
android:title="Camera" />
<androidx.preference.SwitchPreference
android:key="reset"
android:summary="..."
android:title="Reset" />
<androidx.preference.Preference
android:key="key"
android:summary="subtitle"
android:title="title" />
<androidx.preference.Preference
android:key="key2"
android:summary="subtitle2"
android:title="title2" />
<androidx.preference.CheckBoxPreference
android:key="key_for_check_box"
android:summary="subtitle"
android:title="title" />
</androidx.preference.PreferenceCategory>
</PreferenceScreen>
Follow that steps
1. In oncreate you should make default setting and put the in shared prefs like this
SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("Key","Value");
editor.apply();
And here change the flag for if settings are default or not. So first time when user open app everything by default and you set default values when he changed something the flag of default is changing and next time he come back this step ignores
2. On each switcher you have to make check and get value from shared preferences like this.
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
String name = preferences.getString("Key", "Value");
if(!name.equalsIgnoreCase("") && !name.equalsIgnoreCase("default")
{
// Switcher change state
}
Optional: You could optimize it by adding one more flag to check were there any changes after last update in that case just go and update each switcher but this is the easiest way. Either you could check if user open app first time or not by adding on null check
Conclusion: Check if first time just put everything with default values from shared preferences -> than if change switcher state just change the same in shared pref -> when come back to setting activity extract all values from each switcher from shared preferences
So I am trying to implement a preferences menu in my app. I used the standard generated template in android studio. THe issue is that now I can't figure out how save the values the user specifies. I thought about using a click listener to determine when a user clicked a checkbox and then getting the actual value of the checkbox and saving that to sharedpreferences, but I can't figure out how to do it.
Does anyone have any suggestions on how use onClick in a preference activity?
OK, we seem to be on the right track about the system storing the values automatically, but whenever I try to reference them from my main class, it always returns null. Here is my code:
boolean trueorfalse = PreferenceManager.getDefaultSharedPreferences(getActivity())
.getBoolean("my_key", false)
;
So I assume you've already defined your Preferences in res --> xml and it looks something like this:
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:key="my_key"
android:summary="#string/desc_string"
android:title="#string/title_string" />
</PreferenceScreen>
As soon as the user checks or unchecks the CheckBox the systen will automatically create an entry in the default Preference-file which you can access like this:
PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean("my_key", false);
But back to your initial question: If you want to assign an onClick-Listener to your preference you have to do something like this:
Preference myPreference = (Preference) findPreference("my_key");
myPreference .setOnPreferenceClickListener(new OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
// do something
}
});
Note: In this example it isn't a CheckBoxPreference, it's just a simple Preference
I tried the same in my SettingsMenu by implementing OnSharedPreferenceChangeListener
public class SettingsMenu extends PreferenceActivity implements OnSharedPreferenceChangeListener {
#Override
public void onCreate(Bundle savedInstanceState) {
Context context = getApplicationContext();
SharedPreferences menu_settings = PreferenceManager.getDefaultSharedPreferences(context);
menu_settings.registerOnSharedPreferenceChangeListener(this);
...
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
// check the checkboxes
}
}
Hope it helps :)
I have a PreferenceFragment where I have defined a CheckBoxPreference in XML. I need to check this value in a Service, but it always gives me the old value. I noticed the value is correctly changed when I restart the application.
My Preference Fragment :
public class OptionsFragment extends PreferenceFragment
{
public static final String WIFI_ONLY = "wifi";
private SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(MyApplication.getInstance());
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.config);
}
}
My config.xml :
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<CheckBoxPreference
android:defaultValue="true"
android:key="wifi"
android:summary="Check if you want to use wifi only"
android:title="Use Wifi only" />
</PreferenceScreen>
My Service :
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(MyApplication.getInstance());
Log.d(TAG, "isWifiOnly : "+settings.getBoolean(OptionsFragment.WIFI_ONLY, true));
The log always return the same value no matter if I change it or not, except if i restart the app. Also, in my MainActivity I have that line in OnCreate():
PreferenceManager.setDefaultValues(getApplicationContext(), R.xml.config, false);
It creates the config file with the default value if needed.
I'm doing something wrong, the question is what ?
I found a solution thanks to this link Managing SharedPreferences in both PreferenceActivity and Service within same app and thanks to Andrew T. :
The issue was the multi process mode. If you have a Service which is declared in the manifest with a android:process="" (which is my case) then it's necessary to set a multi process mode.
Here is what i did :
in PreferenceFragment :
public static final String CONFIG_NAME = "pref";
...
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getPreferenceManager().setSharedPreferencesName(CONFIG_NAME);
getPreferenceManager().setSharedPreferencesMode(Context.MODE_MULTI_PROCESS);
addPreferencesFromResource(R.xml.config);
...
}
My Service :
SharedPreferences settings = MyApplication.getInstance().getSharedPreferences(OptionsFragment.CONFIG_NAME, Context.MODE_MULTI_PROCESS);
and I set the default values in MainActivity this way :
PreferenceManager.setDefaultValues(getApplicationContext(), OptionsFragment.CONFIG_NAME, Context.MODE_MULTI_PROCESS, R.xml.config, false);
And now it works fine. Hope it will help !
Thank you again Andrew T.
I had the same issue for the last days...
I have a preference.xml with my layout and keys and inflate it into a PreferenceFragment while Listening on changes and thereby informing a Service of my Application of any change.
The crucial part is to set the mode of the SharedPreference access right:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
getPreferenceManager().setSharedPreferencesMode(Context.MODE_MULTI_PROCESS);
}
The Context.MODE_MULTI_PROCESS flag makes commits() apply to all accessing processes so even my Service would get direct access to the just changed values.
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
{
if(SettingsManager.setupIsValid(getActivity())){
Intent startServiceIntent = new Intent(getActivity(), IntentService.class);
startServiceIntent.setAction("PREFERENCES_CHANGED");
getActivity().startService(startServiceIntent);
} else {
Toast.makeText(getActivity(), getString(R.string.settings_incomplete), Toast.LENGTH_SHORT).show();
}
}
This will first do check magic and whenever the settings are valid inform the service of the change.
This allows the usage of multiple processes and always current preference values across all processes.
P.S.: direct access then looks like this
SharedPreferences prefs = context.getSharedPreferences(context.getPackageName() + "_preferences", Context.MODE_MULTI_PROCESS);
Ok i'm following an android book and they are adding settings to a sudoku game using a class that extends PreferenceActivity, this class is called by an intent and all it does is addPreferencesFromResource(R.xml.settings), this approach has been deprecated and its not working anymore, here is the code from the book:
package org.example.sudoku;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class Prefs extends PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.settings);
}
}
Now i have looked into this matter and found that you have to instance a PreferenceManager in order to do this, but in the example i found they extends the Prefs class from PreferenceFragment (not PreferenceActivity as in the book), i managed to work on the code as follows:
/*
* this is for use from API version 11 and after...
*
*/
package org.example.sudoku;
import android.os.Bundle;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
public class Prefs extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Make sure default values are applied. In a real app, you would
// want this in a shared function that is used to retrieve the
// SharedPreferences wherever they are needed.
PreferenceManager.setDefaultValues(getActivity(),
R.xml.settings, false);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.settings);
}
}
But this doesn´t do the job, i don´t know if its because i am calling this class from an intent and this class extends PreferenceFragment instead of PreferenceActivy or this is not the way of doing this thing, can someone help me out to understand this?
final String PREF_SETTINGS_FILE_NAME = "PrefSettingsFile";
To read the values of your preference variables.
SharedPreferences preferences = getSharedPreferences(PREF_SETTINGS_FILE_NAME, MODE_PRIVATE);
prefSettingsValue1= preferences.getInt("value1", 1); // default value of prefSettingsValue1 will be 1 in case you are trying to read a non-existent value. You can specify it according to your wish. (like I have done for the next value)
prefSettingsValue2= preferences.getInt("value2", 0);
prefSettingsValue3= preferences.getInt("value3", 1);
To write values into your preference variables.
SharedPreferences preferences = getSharedPreferences(PREF_SETTINGS_FILE_NAME, MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putInt("vaule1", prefSettingsValue1);
editor.putInt("value2",prefSettingsValue2);
editor.putInt("value3",prefSettingsValue3);
editor.commit();
Note : No need to use any XML file to store the preferences. Just save the values in the Preference variables and read them later in you application. Not just integers, you can also get and put Strings by using getString and putString functions to read and write, respectively. Also, you do not need to extend any Preference Activity/Fragment.
This question has been asked many times in this forum. But I feel it still need to be cleared for me .
public class PrefTest extends Activity {
public Button bt_start= null;
SharedPreferences mSharedPreferences;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.main);
bt_start = (Button) findViewById(R.id.button1);
bt_start.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Log.d("TEST","");
PreferenceManager.setDefaultValues(getApplicationContext(),
R.xml.settings_org, true);
mSharedPreferences = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
Boolean test = false;
test = mSharedPreferences.getBoolean("auto_launch_key", true);
Log.d("TEST","test = "+test);
}
});
super.onCreate(savedInstanceState);
}
#Override
protected void onStart() {
super.onStart();
}
}
In the above code
Log.d("TEST","test = "+test);
always prints true , though I have set default value in xml as false(as below)
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory android:title="settings" >
<CheckBoxPreference android:key="auto_launcvh_key"
android:summaryOn="..."
android:summaryOff="---"
android:title="auto_launch_string" android:defaultValue="false" />
</PreferenceCategory>
</PreferenceScreen>
Am expecting the setDefaultValues to take the defaults values form the XML and initialize the preference.
Am I wrong in my understanding?
UPDATE
On closer inspection I can see you probably aren't correctly retrieving the SharedPreference object. although I have not tried it, to make this test work I assume you would have to call getSharedPreferences (String name, int mode) with the name of your XML file to get the object which stores the values defined in your XML file.
getDefaultSharedPreferences (Context context) states:
Gets a SharedPreferences instance that points to the default file that
is used by the preference framework in the given context. Parameters
context The context of the preferences whose values are wanted.
Returns
A SharedPreferences instance that can be used to retrieve and listen
to values of the preferences.
Your file doesn't seem to be the default file and thus the preferences you are trying to call don't exist.
Generally the way to deal with preferences is to sub class a PreferenceActivity which will create a preferences interface but I appreciate you are just trying to write a simple test.
Also I assume the CheckBoxPreference android:key="auto_launcvh_key"is a typo when writing the question. I think I checked the key when first writing this answer and it was CheckBoxPreference android:key="auto_launch_key"
ORIGINAL
Firstly I would change test = mSharedPreferences.getBoolean("auto_launch_key", true); to test = mSharedPreferences.getBoolean("auto_launch_key", false); if it now returns false then the preference doesn't exist in the system so there is a problem with your environment. Try cleaning the project and re-installing.
Secondly in the docs it states
readAgain - Whether to re-read the default values. Note: this will NOT
reset preferences back to their default values. For that
functionality, use getDefaultSharedPreferences(Context) and clear it
followed by a call to this method with this parameter set to true.
Therefore if the preference already exists in the system as true this will not overwrite and so a re-installation should sort this out as well. or you could try calling clear() on mSharedPreferences and then calling PreferenceManager.setDefaultValues(getApplicationContext(), R.xml.settings_org, true);
If this doesn't work can you post complete XML.
The answer is actually very simple.
Boolean values in a preference file are only present when they are true so when reading the boolean value you need to set default value to false:
test = mSharedPreferences.getBoolean("auto_launch_key", false);
So when the preferences in xml is true it reads true and otherwise uses the default of getBoolean. I noticed while debugging there aren't any Boolean preferences with false as the value.