Based on the following code, can you tell me how to refresh the PreferenceActivity window to show changes in the settings immediately? For example: the user taps the master chime toggle checkbox to true (ticked), I would like the user to immediately see the other settings such as the ChimeOn15Past checkbox also be be true (ticked)
SharedPreferences.Editor prefEditor = clockSettings.edit(); // Allow the settings to be changed.
if (booleanMasterChimeToggle == true) {
prefEditor.putBoolean("ChimeOnTheHour", true);
prefEditor.putBoolean("ChimeOn15Past", true);
prefEditor.putBoolean("ChimeOn30Past", true);
prefEditor.putBoolean("ChimeOn45Past", true);
strNotifyMessage = "Full chiming has now been set.";
} else {
prefEditor.putBoolean("ChimeOnTheHour", false);
prefEditor.putBoolean("ChimeOn15Past", false);
prefEditor.putBoolean("ChimeOn30Past", false);
prefEditor.putBoolean("ChimeOn45Past", false);
strNotifyMessage = "Full chiming has now been disabled.";
}
Nikolay's answer is correct. I just want to add some code here to illustrate his point more clearly.
private CheckBoxPreference mOn15Past;
private CheckBoxPreference mOn30Past;
private CheckBoxPreference mOn45Past;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
mOn15Past = (CheckBoxPreference) findPreference("ChimeOn15Past");
mOn30Past = (CheckBoxPreference) findPreference("ChimeOn30Past");
mOn45Past = (CheckBoxPreference) findPreference("ChimeOn45Past");
final Preference chimeMaster = findPreference("ChimeMaster");
chimeMaster.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
final boolean value = (Boolean) newVal;
mOn15Past.setChecked(value);
mOn30Past.setChecked(value);
mOn45Past.setChecked(value);
return true;
}
});
}
In short, PreferenceActivity
is not designed to refresh its values from the persistent storage once it is started. Instead of using SharedPreferences.Editor
to modify and commit additional changes like you did in your code, it is better to make the changes into the local PreferenceManager
object which will be committed by the PreferenceActivity
in its normal lifecycle.
Instead of
finish();
startActivity(getIntent());
I prefer the following code :
setPreferenceScreen(null);
addPreferencesFromResource(R.xml.preferences);
This will reset the display as well but without the whole finish procedure and its consequences.
Plus this code works well with PreferenceActivity
and PreferenceFragment
.
This is interesting if you would like to change dynamically the locale value for example. In this case, working with the manager is not enough because you want a full reload of titles and values.
EDIT: setPreferenceScreen
is deprecated in PreferenceActivity
(still working) but is not in PreferenceFragment
There's a simple method to refresh all items on the list at once. Simply do the following:
getPreferenceScreen().removeAll();
addPreferencesFromResource(R.xml.preferences);
With this approach you won't loose ListView's position.
Implement onPreferenceChange
and toggle related perfs from there. To 'refresh' the whole activity, you need to finish()
and restart it.
You can simply call onCreate method. If you want you can call onStart and onResume methods.
onCreate(null);
I have solved my problem with this way.
After fighting this for a day, I figured out this.
This is for multiple levels of preferences.
parent is the preference screen that holds the preference you are trying to update.
Since the settings screen displays as a dialog, you can get the listview from the dialog, then tell it's adapter to update child.
PreferenceScreen parent // The screen holding the child
PreferenceScreen child // The entry changing
child.setSummary(isEnabled?"Enabled":"Not Enabled");
ListView v = (ListView)parent.getDialog().findViewById(android.R.id.list);
BaseAdapter ba = (BaseAdapter)v.getAdapter();
ba.notifyDataSetChanged();
I found R.id.list is not available on older phones but this works
ListAdapter adapter = parent.getRootAdapter();
if (adapter instanceof BaseAdapter) {
((BaseAdapter)adapter).notifyDataSetChanged();
}
This class indicate simple preference screen. Which may help you.
public class PreferenceActivitySettings extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
private SharedPreferences preferences;
@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
preferences = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
preferences.registerOnSharedPreferenceChangeListener(this);
}
@SuppressWarnings("deprecation")
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
setPreferenceScreen(null);
addPreferencesFromResource(R.xml.settings);
}
}
I managed to write a method that's actually quite simple and without need for invalidating ListViews or or whatever the situation may be. This method makes a call to the public ViewGroup removeView(View view)
, View requestLayout()
, View forceLayout()
, ViewGroup addView(View view)
, and finally a call to Fragment OnCreate(Bundle savedInstanceState)
methods with a few null checks and a final View
temporary variable to store the actual view when the view is removed.
This method is still quite new and I'll be giving it some tweaking and refining over the next 2 days but it works flawlessly as is with no whack side effects. Since the class I've written holding the code changes the actual preference title and summary text styles for the whole rom (that was the whole point to the options I've added), I've also added a public constructor the classes that are activities that lie in the activity stack below the preference style screen so they can be updated at the same time. Most likely I will be moving this new method into the frameworks view class so it can be made available system wide.
public void reLoadView(View view) {
if (view == null) {
view = mView;
Log.i(TAG, "The current View is: " + view);
}
final View tmpView = view;
try {
setStyleChanged(1);
setReset(0);
Log.i(TAG, "The Temporary View is: " + tmpView);
Log.i(TAG, "The current View is: " + mView);
Log.i(TAG, "The current ViewGroup is: " + mViewGroup);
if (mView != null) {
if (mViewGroup != null) {
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
mViewGroup.removeView(mView);
mView.requestLayout();
mView.forceLayout();
mViewGroup.addView(tmpView);
onCreate(new Bundle());
}
});
}
}
View tmp = null;
mDemented.reLoadView(tmp);
} catch (Exception e) {
}
}
The view variables themselves are set initially in the class initialization and are initialized and defined in the View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
and the View onViewCreated(View view, Bundle savedInstanceState)
. The view variables themselves are set initially in the class initialization.
private View mView;
private ViewGroup mViewGroup;
private int mLayoutResId = R.layout.preference_list_fragment;//holds the layout reference just to keep it clean
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
View rootView = inflater.inflate(mLayoutResId, parent, false);
mViewGroup = parent;
return rootView;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
mView = view;
}
In the activities in the stack below, my PreferenceStyle class, I set an empty constructor which can be initialized anywhere in the app.
public class DEMENTED extends SettingsPreferenceFragment implements
Preference.OnPreferenceChangeListener, View.OnClickListener {
public DEMENTED() {
super();
}
//other code to do whatever here
In my PreferenceStyle class I imported my DEMENTED class then set it as a variable prior to onCreate(Bundle savedInstanceState)
:
private DEMENTED mDemented;
Then initialized the variable in onCreate(Bundle savedInstanceState)
:
mDemented = new DEMENTED();
The call to my DEMENTED class to reload its view is done in my reloadView(View view)
method but the variable view used to make the call is a View variable set immediately prior to the call and is set as null:
View tmp = null;
mDemented.reLoadView(tmp);
and my DEMENTED class checks to see if the included View in the method call is null and if so sets it to a localized View variable so the method can do its work with local variables:
public void reLoadView(View view) {
if (view == null) {
view = mView;
Log.i(TAG, "The current View is: " + view);
}
//all the other good stuff here
Basically, this uses the ViewGroup as defined in onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
:
mViewGroup = parent;
and View variable is set in onViewCreated(View view, Bundle savedInstanceState)
mView = view;
Hope this helps someone out because this has been a question I've seen repeated on here over and over and I have yet to find a solid solution basically anywhere that didn't involve multiple classes used as utils. If anyone has any comment suggestions to simplify or whatever feel free to comment.
After you commit the changes to the sharedPreferences, I think you should just call invalidateHeaders() . Docs about it:
Call when you need to change the headers being displayed. Will result
in onBuildHeaders() later being called to retrieve the new list.
This should refresh the UI, to show the new values.
If you're targeting API 11 and above, you can use invalidateHeaders
.
From the docs:
Call when you need to change the headers being displayed. Will result
in onBuildHeaders() later being called to retrieve the new list.