onSharedPreferenceChanged() Never called - android

I recently imported the HoloEverywhere library from GitHub into Eclpse and have begun using it in an app that has already been working. Overall I am happy with the library and things have been going well.
I am trying to use the org.holoeverywhere.preference.PreferenceActivity in place of my old PreferenceActivity. The UI looks as it should, but I noticed that onSharedPreferenceChanged() never gets called anymore. What am I doing wrong?
AFAIK I am using the library as intended. I have barely changed anything from my old version to the new version using HoloEverywhere. While there are many related questions on SO, I could not find anything that addresses my problem.
Relevant code posted below:
import org.holoeverywhere.LayoutInflater;
import org.holoeverywhere.preference.Preference;
import org.holoeverywhere.preference.PreferenceFragment;
import org.holoeverywhere.preference.PreferenceManager;
import org.holoeverywhere.preference.PreferenceScreen;
import org.holoeverywhere.preference.SharedPreferences;
import org.holoeverywhere.preference.SharedPreferences.Editor;
import org.holoeverywhere.preference.SharedPreferences.OnSharedPreferenceChangeListener;
public class SettingsActivity extends org.holoeverywhere.preference.PreferenceActivity implements SyncManager.SyncProgressListener, SharedPreferences.OnSharedPreferenceChangeListener
{
private static SharedPreferences prefs;
#Override
public void onCreate(Bundle savedInstanceState)
{
prefs = PreferenceManager.getDefaultSharedPreferences( this );
}
public void onSharedPreferenceChanged(SharedPreferences prefs, String key)
{
// do some really important stuff here
}
public static class DisplaySetttingsFragment extends PreferenceFragment
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate( savedInstanceState );
getActivity().setTitle( getString( R.string.pref_display_title ) );
addPreferencesFromResource( R.xml.display_preferences );
}
#Override
public void onResume()
{
super.onResume();
prefs.registerOnSharedPreferenceChangeListener( (SettingsActivity) getActivity() );
}
#Override
public void onPause()
{
super.onPause();
prefs.unregisterOnSharedPreferenceChangeListener( (SettingsActivity) getActivity() );
}
}
}
Update: An example where I change and commit preferences and I would expect onSharedPreferenceChanged() to be called
#Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)
{
String resetString = getString( R.string.pref_key_reset_display );
String key = preference.getKey();
if ( key != null && key.equals( resetString ) )
{
prefs.edit().
putBoolean( getString( R.string.pref_key_reset_display ), true ).commit();
}
return super.onPreferenceTreeClick( preferenceScreen, preference );
}
Update: I do not believe this is a problem of my preferences not having a registered listener (in this case my SettingsActivity) at the time of a commit() or apply(). I am able to debug and see that the WeakHashMap inside prefs for listeners always has my activity as a member. I have tried creating an global variable that is a listener, but it makes no difference.

The might be missing the below calls: this might solve your problem.
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
/* (non-Javadoc)
* #see android.app.Activity#onPause()
*/
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
}

try to call
prefs.registerOnSharedPreferenceChangeListener(this)
in onCreate in SettingsActivity. Calling it in Fragment, in inner class, will destroy the listeners when inner fragment is Paused, I suppose

Check the preference.xml. All the preferences have a defined key value? If not the callback will not be fired.

I had a similar problem. For me the listener was called for a standard property but nor for one set with the editor.
The solution came from the doku for the listener
This may be called even if a preference is set to its existing value.
The solution for me was setting the boolean first to the wrong and then to the correct value(and committing each change).

Related

NullPointerException accessing activity from PreferenceFragment

Edit: Changing the language results in SettingsActivity.onCreate being called twice: (1) Due to recreate() and (2) due to context change.
However SettingsFragment.onCreate is being called only once, which kind of explains below question. But why isnt't SettingsFragment.onCreate being called after the second execution of the SettingsActivity.onCreate?
I am quite new to Android development and want to understand the reason which makes my application crash:
Within a settings activity I have placed a PreferenceFragment which allows the user to change the UI language. In order to take effect and not to spoil the back stack I call the recreate() method of the fragment's activity.
The first implementation looked like below:
(A)
public class SettingsActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SettingsFragment fragment = new SettingsFragment();
getFragmentManager().beginTransaction().replace(android.R.id.content, fragment).commit();
getFragmentManager().executePendingTransactions();
fragment.setActivity(this);
}
public static class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener
{
Activity m_activity;
public void setActivity(Activity activity){
m_activity = activity;
}
#Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
SharedPreferences preferences = getPreferenceScreen().getSharedPreferences();
preferences.registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
...
m_activity.recreate();
}
}
}
Sometimes above solution works, sometimes m_activity is Null and the application crahes. As a possible alternative solution I removed the 'setActivity' setter and called 'getActivity' within onSharedPreferenceChanged:
(B)
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
...
getActivity().recreate();
}
But this also results in sporadic NullPointerExceptions.
In scenario (B) I found that the fragment's 'onAttach' is not being called for any reason sometimes and hence 'getActivity' returns null. However I would expect scenario (A) not to crash since this isn't Null in onCreate?
Problem solved!
For those who have the same problem: I had to unregister the onSharedPreferenceChanged listener in SettingsFragment.onDestroy.

Android PreferenceFragment, best practice for persistent UI update?

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

Best place to put onSharedPreferenceChangeListener

I am trying to add a setting to my app. I have added the new setting but I am not sure where to put OnSharedPreferenceChangeListener. I put it in the activity and added a Log.d(), but the Log.d() is never triggered. Any ideas?
The best place according to Android Settings doc would be:
#Override
protected void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
#Override
protected void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
}
And you should store the listener in a field variable (or use the Activity object itself - as in the above source code), so that it does not get garbage collected.
I.e. an anonymous class object can't be used as OnSharedPreferenceChangeListener.
You need to register your listener by invoking setOnPreferenceChangeListener. I'm going to assume that you have an Activity class that extends PreferenceActivity. If so, that is the best place for your listener. You'd write something like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
Preference myPreference = findPreference("my_pref");
myPreference.setOnPreferenceChangeListener(this);
}

Android preferences changed

I have some preferences in my activity and I would like to achieve that, depending on these preferences, some services will be initiated or not.
I am trying to implement and onSharedPreferenceChangedmethod, but it never gets called (even if I have assigned it to a field).
The code is the following:
public class MtprojectActivity extends Activity {
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prefs = PreferenceManager.getDefaultSharedPreferences(this);
callsCheckbox = prefs.getBoolean("callsLogChk", true);
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (!started) {
startCallsService();
bindCallsService();
} else {
releaseCallsService();
stopCallsService();
}
}
};
prefs.registerOnSharedPreferenceChangeListener(listener);
Thanks a lot in advance!
Are you sure it isn't being called or is it just a case of it not doing what you expect? I may be wrong but shouldn't the code look like this...
if (key.equals("callsLogChk")) {
if (!started) { // Check NOT started ???
startCallsService();
bindCallsService();
}
else { // The 'else' should compliment the check for !started ???
releaseCallsService();
stopCallsService();
}
}
Sorry, as I don't know your code I may be totally wrong but as you've posted it, it doesn't look quite right to me.
EDIT:
Also, are you making sure you call the SharedPreferences.Editor.commit() method when you make the change to the preference?

onSharedPreferenceChanged called multiple times.... why?

I have a preference Activity, at first when I chance a preference the onPreferenceChange is triggered once as expected.
However, after some time (going to different activities and such) the onPreferenceChange is called twice.
I see in the debugger that the WeakHashMap for the mListeners is 1 in the beginning and then becomes greater than 1, but not sure why?
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getPrefs();
int preferencesResource = 0; // R.xml.preferences;
preferencesResource = getResources().getIdentifier("pref", "xml",
getPackageName());
addPreferencesFromResource(preferencesResource);
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(SharedPreferences arg0,
String arg1) {
// Why is this called once then sometimes twice!!
Log.i("PreferencesActivity", "OnPreferenceChanged()");
}
};
prefs.registerOnSharedPreferenceChangeListener(listener);
}
protected void onDestroy() {
super.onDestroy();
listener = null;
prefs.unregisterOnSharedPreferenceChangeListener(listener);
prefs = null;
}
public Preferences getPrefs() {
if (prefs == null) prefs = new Preferences(this);
return prefs;
}
You've placed unregisterOnSharedPreferenceChangeListener() in onDestroy() and it's not called on all activity restarts.
Look at the activity lifecycle diagram. Conclusion is that proper way to do this is to place registerOnSharedPreferenceChangeListener() and unregisterOnSharedPreferenceChangeListener() in onResume() and onPause() respectively.
This isn't for a LiveWallpaper by any chance is it? It sounds to me like you have two instances of the same class running(I.E. The LiveWallpaper itself as well as the preview because you're in settings). If it seems like they happen instantly right on top of each other and there is no delay than most likely you have the same listener running twice.

Categories

Resources