Preference key always return null - android

I have a Preference Screen in my android app which contains a call to the system settings via an inner Preference and some Switches options as below:
<PreferenceCategory
android:title="#string/preferences_activity_supervisor_settings_title">
<Preference
android:key="#+id/instrument_preference"
android:title="#string/instrument_settings"
android:summary="#string/instrument_settings">
</Preference>
<com.CustomSwitchPreference
android:key="#string/prefs_super_autosend_key"
android:title="#string/prefs_super_autosend_title"
android:summary="#string/prefs_super_autosend_summary"
android:defaultValue="false"/>
...
...
My class extends PreferenceFragment and I added the resources using addPreferencesFromResource(). It works without problems.
However, the method onPreferenceTreeClick(), when I click in the Fragment (keyID = instrument_preference) the preferences always brings me key as NULL. All other options in the preference fragment I can read the key.
The question is why and how I detect the user clicked in the first element of my preference list ?

First remove + from #+id, because every time it create a new key due to #+id, thats why you get null.
And to detect SharedPreference is changed use this simple code:
public class MyPreferences extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.fw_preferences); //deprecated
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
// handle the preference change here
}
}

Try removing #+id before the preference key name
It should be like
<Preference
android:key="instrument_preference"
android:title="#string/instrument_settings"
android:summary="#string/instrument_settings">
</Preference>

Related

how to implement settings in android

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

Can't resolve findPreference() from MainActivity?

I'm getting a compiler error cannot resolve method findPreference when I try to intialize an OnSharedPreferencesChanged listener in my MainActivity. According to the answer here:
findPreference() should be called from a class implementing PreferenceActivity interface
but I don't understand what the code to do this would be. How can I get rid of the compiler error and successfully set listeners for preference changes?
MainActivity.java
public class MainActivity extends FragmentActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
private SharedPreferences.OnSharedPreferenceChangeListener listener;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
//Test preference menu
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.equals("pref_wood")) {
Preference woodPref = findPreference(key); //COMPILER ERROR HERE
MainActivity.getGLSurfaceView().setTexture("");
// Set summary to be the user-description for the selected value
woodPref.setSummary(sharedPreferences.getString(key, ""));
}
}
}
}
}
findPreference is a method which is part of both PreferenceFragment and PreferenceActivity - these are the Fragments/Activities that actually show your Preference screen (the activity is deprecated and you should be using the PreferenceFragment).
You're trying to use it in your MainActivity. This doesn't work because the Preference objects don't actually exist on this screen (they exist in another activity that usually have a PreferenceFragment as part of it). If you need to get access to a preference value of a preference in an activity that is not your preference screen, use SharedPreferences, something like:
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
int defaultValue = getResources().getBoolean(R.bool.saved_high_score_default);
boolean wood = sharedPref.getBoolean(pref_wood, defaultValue);
You can check out the documentation for further examples.
If your MainActivity is supposed to be a screen that shows settings, then you should probably rename it and include a preference fragment inside of it.
I believe you're also going to run into trouble with setSummary because the Preference is not part of this activity, it's part of the activity where you actually modify the preferences. setSummary is used to update the actual UI of the Preference so that if you, for example, select one of three values when using a list preference, it shows the value you just selected on the screen.

Handling clicks in PreferenceActivity

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 :)

Retrieving the preferences from the xml file in Android

I am new to Android and I am trying to handle the settings according to the instructions in
http://developer.android.com/guide/topics/ui/settings.html
I used the fragment based solution as the one directly in the activity was deprecated:
public class SettingFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
}
}
public class SettingsActivity extends PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Display the fragment as the main content.
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new SettingFragment())
.commit();
}
}
The settings are correctly displayed in the app, yet when I try to retrieve their values with:
sharedPref= PreferenceManager.getDefaultSharedPreferences(Dashboard.dashboard);
startDayTime=sharedPref.getString(SettingsActivity.day_switch_start, "");
startNightTime=sharedPref.getString(SettingsActivity.night_switch_start, "");
it complaints that values day_switch_start and night_switch_start might not be resolved. In fact, when I explode the values recognized by SettingActivity, I get a long list of capitalized strings part of the standard settings, but not my own strings.
Those were in fact just entered in the xml file and linked from the SettingFragment, so I doubt context Dashboard.dashboard I passed has any reference to it. Yet there are no instructions on how to pass the settings references to a specific context and moreover they say that the settings should be available from anywhere. I am stuck, any solution?
Thanks,
Please check the reference you linked again, especially the Reading Preferences section. When you set the preference key to, e.g., day_switch_start then you must use the same String when reading the preference, e.g.,
startDayTime=sharedPref.getString("day_switch_start", "");
You can also store the preference key to a constant like in the linked example:
public class SettingsActivity extends PreferenceActivity {
public static final String KEY_PREF_DAY_SWITCH_START = "day_switch_start";
// ...
and then access it when reading the preference:
startDayTime=sharedPref.getString(SettingsActivity.KEY_PREF_DAY_SWITCH_START, "");
Edit: I'm not sure what Dashboard.dashboard should represent but this should work:
sharedPref= PreferenceManager.getDefaultSharedPreferences(this);

Default Shared Preferences give me wrong values in Service

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);

Categories

Resources