My preference values aren't saving and everytime I read the SharedPreferences file it returns default values; changes are supposed to be automatically handled by the system when a user makes a choice (like selecting an option in a ListPreference) so I don't know why this isn't happening in my app.
According to google
"When the user changes a setting, the system updates the corresponding value in the SharedPreferences file for you. The only time you should directly interact with the associated SharedPreferences file is when you need to read the value in order to determine your app's behavior based on the user's setting."
Should I be manipulating a SharedPreference.Editor instance in my OnSharedPreferenceChangeListener or is there something else I need to do to make values of user settings persist?
The Problem in Code: As a result of this misunderstanding, my code doesn't persist user settings values (the default value is always chosen when I read the SharedPreference file in my MainActivity's OnCreate). As it is now, the buttons chosen in my Preferences menu View persist upon app restarts, but it seems that choosing an option in this menu doesn't save key values to the SharedPreferences file.
What do I need to do to make the values set by the user in my ListPreference persist?
MainActivity
public class MainActivity extends FragmentActivity {
private static int prefWoodColor; //saved pref variable for OpenGL neck texture
private SharedPreferences settings;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
//Restore preferences
settings = PreferenceManager.getDefaultSharedPreferences(this);
prefWoodColor = Integer.parseInt(settings.getString(this.KEY_PREF_WOOD_TYPE, "Maple"));
...
}
}
Preferences Activity
public class FragmentSettingsMenu extends com.takisoft.fix.support.v7.preference.PreferenceFragmentCompat {
private SharedPreferences.OnSharedPreferenceChangeListener listener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from the XML resource
addPreferencesFromResource(R.xml.preferences);
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.equals("pref_wood")) {
Preference woodPref = findPreference(key);
String color = woodPref.getSharedPreferences().getString(key, "Maple");
//Should I be calling edit.apply() logic here?
}
}
};
}
...
}
Preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
android:title="Settings"
<ListPreference
android:key="pref_wood"
android:title="#string/pref_wood"
android:dialogTitle="#string/pref_wood"
android:entries="#array/pref_wood_entries"
android:entryValues="#array/pref_wood_values"
android:defaultValue="#string/pref_wood_default" />
</PreferenceScreen>
Strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">MyApp</string>
<string name="dummy_button">Dummy Button</string>
<string name="dummy_content">DUMMY\nCONTENT</string>
<!--Preference Menu Strings-->
<string name="pref_wood">Wood Style</string>
<string-array name="pref_wood_entries">
<item>"Maple"</item>
<item>"Cedar"</item>
<item>"Oak"</item>
</string-array>
<string-array name="pref_wood_values">
<item >0</item>
<item >1</item>
<item >2</item>
</string-array>
<string name="pref_wood_default">Maple</string>
</resources>
The system saves changes automatically!
Related
Im making wallpaper app which it has a setting button for users which could adjust how many circle can be drawn on the wallpaper. Here i set 5 as default value in the preferences.xml . When i install the app,the wallpaper constructor get the number of circles in preference.xml which just 0 and i have to manually press setting button and set the number. So I want the keep the number is 5 ( default) when installing the app.
Some class that use for the App:
preferences.xml
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<EditTextPreference android:key="numofparticles" android:title="Number of particles" android:summary="Chose a initial particle's number" android:defaultValue="5">
</EditTextPreference>
</PreferenceScreen>
Prefernces.java
public class Preferences extends PreferenceActivity {
public static String numofparticles="numofparticles";
public static String image="getimage";
private static final int Pic_image=1;
private SharedPreferences.OnSharedPreferenceChangeListener PreferenceChangeListener;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
PreferenceChangeListener=new SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
if (s.equals(numofparticles) && s.getClass().getSimpleName()=="Interger")
{
Preference numofP=findPreference(s);
numofP.setSummary(sharedPreferences.getString(s,"")+ " Particles");
Toast.makeText(getApplicationContext(),"success",Toast.LENGTH_SHORT);
}
}
};
Snippet from another class which i get this preference data.
public wallpaperengine()
{
display.getRealSize(size);
wallpaper_height=size.y;
wallpaper_width=size.x;
background=BitmapFactory.decodeResource(getResources(),R.drawable.particlebackground);
background=Bitmap.createScaledBitmap(background,wallpaper_width,wallpaper_height,true);
sharedPreferences= PreferenceManager.getDefaultSharedPreferences(particlewallpaper.this);
sharedPreferences.registerOnSharedPreferenceChangeListener(listener);
num_particle=Integer.valueOf(sharedPreferences.getString(Preferences.numofparticles,"5"));
handler.post(drawFrames);
}
The default 5 is in the layout file (which resides in xml folder of AS) for your preferences activity.
Not in the real preferences data file which resides in /data/data/package/shared_prefs/package_preferences.xml.
The wallpaper code reads from the real data file.
Not from the layout file.
And you know that that activity and layout file are not needed 'to work with shared preferences'.
I have an issue, i have to set a whole host of settings prior to running my main app. These are done through an on-boarding process, however this is not being reflected in my main settings once in the main app.
During on-boarding i set:
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
int radioId = checkedId;
radioButton = getActivity().findViewById(radioId);
String str = (String) radioButton.getText();
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(MyApplication.getAppContext());
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(kDirection, str).apply();
editor.commit();
}
});
My Preference:
<PreferenceCategory app:title="Directions">
<ListPreference
app:key="kDirectionSetting"
app:entryValues="#array/directions"
android:entries="#array/directions"
app:useSimpleSummaryProvider="true"
app:title="Direction Preference"
/>
</PreferenceCategory>
This is reflected in my preferences If i open them in device file explorer before i open the preferences screen. Then when the main menu is opened and the preference screen loaded the String is changed to an unset default value from my array, the same every time.
How do i get the reflected changes to show in my settings first time?
I think that if you have the same key for both your ListPreference and the initial Preference value that you stored, then you will get the ListPreference to edit the initial value. However, do this to set the default value to the ListPreference:
#Override
public void onCreate(Bundle savedInstanceState) {
ListPreference kDirectionPref = (ListPreference) findPreference("kDirectionSetting");
kDirectionPref.setDefaultValue(prefs.getString("kDirection"));
So basically, what I'm saying is that you should ensure that you use the same key to put values for your Preference, i.e. in the first piece of code, kDirection should be changed to "kDirectionSetting".
I would like to create a new activity that includes more buttons. Each button represents a color. How can I change the action bar (and save) if I click on a button that represents a color (red for example)?
I did something that changes the color of the action bar, but if I go on the home page, the color will change again. Do I need to serialize something? Thanks!
pink.setOnClickListener(new View.OnClickListener(){
public void onClick(View view){
getSupportActionBar().setTitle("Pink");
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.colorPink)));
if(Build.VERSION.SDK_INT >=Build.VERSION_CODES.LOLLIPOP){
Window window =getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(getResources().getColor(R.color.colorAccent));
}
}
});
Button xml.
<Button android:id="#+id/button_pink" android:layout_width="296dp"
android:layout_height="49dp" android:layout_marginTop="26dp"
android:background="#color/colorPink" android:text="pink"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent" />
</android.support.constraint.ConstraintLayout>
Read the documentation first. As written in the documentation.
<resources>
<style name="MyTheme" parent="#android:style/Theme.Holo.Light">
<item name="android:actionBarStyle">#style/MyActionBar</item>
</style>
<style name="MyActionBar" parent="#android:style/Widget.Holo.Light.ActionBar">
<item name="android:background">ANY_HEX_COLOR_CODE</item>
</style>
</resources>
And, set "MyTheme" as theme for application / activity.
This is happening because when you restart your activity then according to activity life cycle onReStart() and then onStart() is called so the action bar color becomes default. As in your code you are setting action bar color on a click event.
Possible solution is that in your button click event you can save the color value in a shared preference and then use that shared preference in your onCreate() with the color changing code. This will make your app to set the color that is saved previously.
Android Lifecycle
Shared Preference
onCreate(){
sharedPreferences = getSharedPreferences("NAME", Context.MODE_PRIVATE);
int color = sharedPreferences.getInt("color", "DEFAULT_COLOR");
String title = sharedPreferences.getString("text", "DEFAULT_TEXT");
getSupportActionBar().setTitle(title);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(getResources().getColor(USE_THE_COLOR_VALUE_HERE)));//
if(Build.VERSION.SDK_INT >=Build.VERSION_CODES.LOLLIPOP){
Window window =getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(getResources().getColor(R.color.colorAccent));
}
}
And in your button click store the color and title
onclick(){
SharedPreferences.Editor editor = sharedPreferences.edit();
editor = sharedPreferences.edit();
editor.putString("text","YOUR_TEXT");
editor.putInt("color","YOUR_COLOR");
editor.commit();
}
If you still face any problem in saving your color in shared preference you can see
How to store color value in SharedMemory?
onClick button color changer
int color = R.color.colorPink;
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(getResources().getColor(color)));
And save onClick
SharedPreferences preferences = getSharedPreferences ("prefKey", MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putInt ("colorValue", color);
editor.apply ();
onCreate
SharedPreferences preferences = getSharedPreferences ("prefKey", Mode_Private);
int color = preferences.getInt ("colorValue", 0);
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(getResources().getColor(color)));
I am trying to build an android app and I need a MultiSelectListPreference option in the settings menu. I have created a PreferenceActivity to handle this and I created a preferences.xml file as well, but I need to be able to load the list elements dynamically in the program. I know that I need to use the setEntries and setEntryValues methods to do this, but when I use these methods no exceptions are thrown and the title and summary of the MultiSelectListPreferenc show up but no elements appear.
I have verified that the arrays I am using to populate entries and entryValues are not empty by printing them out, as well as by printing out the result of getEntries() and getEntryValues() after having set them and both these show the entry list to be populated; however no elements show up.
My preferences.xml code:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<MultiSelectListPreference
android:key="markedApps"
android:title="Targeted Apps"
android:summary="Select apps to conditionally disable" />
</PreferenceScreen>
My AppSettings.java code:
public class AppSettings extends PreferenceActivity {
public static MultiSelectListPreference blocked;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
blocked = new MultiSelectListPreference(this);
getFragmentManager().beginTransaction().replace(android.R.id.content, new PrefFrag()).commit();
}
public static class PrefFrag extends PreferenceFragment {
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
MultiSelectListPreference blocked = (MultiSelectListPreference)findPreference("markedApps");
if (blocked == null)
Log.e("NullPointerException", "Blocked is null");
AppSelector.populateAppList();
CharSequence[] appNames = new CharSequence[AppSelector.Data.appNames.size()];
CharSequence[] allApps = new CharSequence[AppSelector.Data.allApps.size()];
int i = 0;
for (String appName : AppSelector.Data.appNames)
appNames[i++] = (CharSequence) appName;
i = 0;
for (String app : AppSelector.Data.allApps)
allApps[i++] = (CharSequence) app;
blocked.setEntries(appNames);
blocked.setEntryValues(allApps);
}
}
}
Thank you in advance for any help you provide.
Wow so I feel extremely stupid now. Turns out my problem was that I expected the list to show up under the title and summary whereas you actually have to click on the title and summary to make the list pop up.
I'm new in the "Android-App-Dev"-Scene and got one question:
How do I easily make a good clean looking settings page for my app?
There are some kind of headlines and some kind of big buttons on you can tab to go to a new page.
I'm using Android Studio and know how to create a new page, class etc..
As of 2019 the recommended way to do this is to use the AndroidX Preference Library.
PreferenceActivity is actually deprecated in API Level 29 (source):
This class was deprecated in API level 29.
Use the AndroidX Preference Library for consistent behavior across all devices. For more information on using the AndroidX Preference Library see Settings.
For a working minimal example please refer to this example in the official docs.
Use PreferenceActivity
sample code from the developer site:
public class PreferenceWithHeaders extends PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Add a button to the header list.
if (hasHeaders()) {
Button button = new Button(this);
button.setText("Some action");
setListFooter(button);
}
}
/**
* Populate the activity with the top-level headers.
*/
#Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.preference_headers, target);
}
/**
* This fragment shows the preferences for the first header.
*/
public static class Prefs1Fragment 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.advanced_preferences, false);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.fragmented_preferences);
}
}
/**
* This fragment contains a second-level set of preference that you
* can get to by tapping an item in the first preferences fragment.
*/
public static class Prefs1FragmentInner extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Can retrieve arguments from preference XML.
Log.i("args", "Arguments: " + getArguments());
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.fragmented_preferences_inner);
}
}
/**
* This fragment shows the preferences for the second header.
*/
public static class Prefs2Fragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Can retrieve arguments from headers XML.
Log.i("args", "Arguments: " + getArguments());
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preference_dependencies);
}
}
}
The preference_headers resource describes the headers to be displayed and the fragments associated with them. It is:
<header android:fragment="com.example.android.apis.preference.PreferenceWithHeaders$Prefs1Fragment"
android:icon="#drawable/ic_settings_applications"
android:title="Prefs 1"
android:summary="An example of some preferences." />
<header android:fragment="com.example.android.apis.preference.PreferenceWithHeaders$Prefs2Fragment"
android:icon="#drawable/ic_settings_display"
android:title="Prefs 2"
android:summary="Some other preferences you can see.">
<!-- Arbitrary key/value pairs can be included with a header as
arguments to its fragment. -->
<extra android:name="someKey" android:value="someHeaderValue" />
</header>
<header android:icon="#drawable/ic_settings_display"
android:title="Intent"
android:summary="Launches an Intent.">
<intent android:action="android.intent.action.VIEW"
android:data="http://www.android.com" />
</header>
The first header is shown by Prefs1Fragment, which populates itself from the following XML resource:
<PreferenceCategory
android:title="#string/inline_preferences">
<CheckBoxPreference
android:key="checkbox_preference"
android:title="#string/title_checkbox_preference"
android:summary="#string/summary_checkbox_preference" />
</PreferenceCategory>
<PreferenceCategory
android:title="#string/dialog_based_preferences">
<EditTextPreference
android:key="edittext_preference"
android:title="#string/title_edittext_preference"
android:summary="#string/summary_edittext_preference"
android:dialogTitle="#string/dialog_title_edittext_preference" />
<ListPreference
android:key="list_preference"
android:title="#string/title_list_preference"
android:summary="#string/summary_list_preference"
android:entries="#array/entries_list_preference"
android:entryValues="#array/entryvalues_list_preference"
android:dialogTitle="#string/dialog_title_list_preference" />
</PreferenceCategory>
<PreferenceCategory
android:title="#string/launch_preferences">
<!-- This PreferenceScreen tag sends the user to a new fragment of
preferences. If running in a large screen, they can be embedded
inside of the overall preferences UI. -->
<PreferenceScreen
android:fragment="com.example.android.apis.preference.PreferenceWithHeaders$Prefs1FragmentInner"
android:title="#string/title_fragment_preference"
android:summary="#string/summary_fragment_preference">
<!-- Arbitrary key/value pairs can be included for fragment arguments -->
<extra android:name="someKey" android:value="somePrefValue" />
</PreferenceScreen>
<!-- This PreferenceScreen tag sends the user to a completely different
activity, switching out of the current preferences UI. -->
<PreferenceScreen
android:title="#string/title_intent_preference"
android:summary="#string/summary_intent_preference">
<intent android:action="android.intent.action.VIEW"
android:data="http://www.android.com" />
</PreferenceScreen>
</PreferenceCategory>
<PreferenceCategory
android:title="#string/preference_attributes">
<CheckBoxPreference
android:key="parent_checkbox_preference"
android:title="#string/title_parent_preference"
android:summary="#string/summary_parent_preference" />
<!-- The visual style of a child is defined by this styled theme attribute. -->
<CheckBoxPreference
android:key="child_checkbox_preference"
android:dependency="parent_checkbox_preference"
android:layout="?android:attr/preferenceLayoutChild"
android:title="#string/title_child_preference"
android:summary="#string/summary_child_preference" />
</PreferenceCategory>
Note that this XML resource contains a preference screen holding another fragment, the Prefs1FragmentInner implemented here. This allows the user to traverse down a hierarchy of preferences; pressing back will pop each fragment off the stack to return to the previous preferences.
See PreferenceFragment for information on implementing the fragments themselves.