How do you refresh PreferenceActivity to show chan

2020-02-09 01:14发布

问题:

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.";
}

回答1:

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.



回答2:

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



回答3:

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.



回答4:

Implement onPreferenceChange and toggle related perfs from there. To 'refresh' the whole activity, you need to finish() and restart it.



回答5:

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.



回答6:

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


回答7:

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


回答8:

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.



回答9:

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.



回答10:

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.