Как обновить PreferenceActivity, чтобы показать изменения в настройках?

Основываясь на следующем коде, можете ли вы сказать мне, как обновить окно PreferenceActivity, чтобы немедленно отобразить изменения в настройках? Например: пользователь устанавливает флажок основного переключателя перезвона в значение true (отмечен галочкой), я бы хотел, чтобы пользователь сразу же увидел, что другие параметры, такие как флажок ChimeOn15Past, также будут иметь значение true (отмечен галочкой)

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

10 ответов

Решение

Николай ответ правильный. Я просто хочу добавить код, чтобы проиллюстрировать его точку зрения более четко.

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

    });
}

Короче, PreferenceActivity не предназначен для обновления его значений из постоянного хранилища после его запуска. Вместо того, чтобы использовать SharedPreferences.Editor Чтобы изменить и зафиксировать дополнительные изменения, как вы сделали в своем коде, лучше сделать изменения в локальном PreferenceManager объект, который будет совершен PreferenceActivity в своем нормальном жизненном цикле.

Вместо

finish();
startActivity(getIntent());

Я предпочитаю следующий код:

setPreferenceScreen(null);
addPreferencesFromResource(R.xml.preferences);

Это также сбросит отображение, но без всей процедуры завершения и ее последствий. Плюс этот код хорошо работает с PreferenceActivity а также PreferenceFragment,

Это интересно, если вы хотите динамически изменить значение локали, например. В этом случае работы с менеджером недостаточно, поскольку требуется полная перезагрузка заголовков и значений.

РЕДАКТИРОВАТЬ: setPreferenceScreen устарела в PreferenceActivity (все еще работает), но не в PreferenceFragment

Есть простой способ обновить все элементы в списке одновременно. Просто сделайте следующее:

getPreferenceScreen().removeAll();
addPreferencesFromResource(R.xml.preferences);

При таком подходе вы не потеряете позицию ListView.

Вы можете просто вызвать метод onCreate. Если вы хотите, вы можете вызвать методы onStart и onResume.

onCreate(null);

Я решил свою проблему таким образом.

Воплощать в жизнь onPreferenceChange и переключать связанные перфорации оттуда. Чтобы "освежить" всю активность, вам нужно finish() и перезапустите его.

После борьбы с этим в течение дня, я понял это.
Это для нескольких уровней предпочтений.

parent - это экран настроек, который содержит настройки, которые вы пытаетесь обновить.

Поскольку экран настроек отображается в виде диалогового окна, вы можете получить список из диалогового окна, а затем сообщить его адаптеру для обновления дочернего элемента.

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

Я обнаружил, что R.id.list недоступен на старых телефонах, но это работает

    ListAdapter adapter = parent.getRootAdapter();
    if (adapter instanceof BaseAdapter) {
        ((BaseAdapter)adapter).notifyDataSetChanged();
    }

Этот класс указывает на простой экран настроек. Который может вам помочь.

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

Мне удалось написать метод, который на самом деле довольно прост и без необходимости аннулирования ListViews или какой-либо другой ситуации. Этот метод делает вызов public ViewGroup removeView(View view), View requestLayout(), View forceLayout(), ViewGroup addView(View view)и, наконец, звонок в Fragment OnCreate(Bundle savedInstanceState) методы с несколькими нулевыми проверками и final View временная переменная для хранения фактического представления при удалении представления.

Этот метод все еще довольно новый, и я буду давать ему некоторые настройки и усовершенствования в течение следующих 2 дней, но он работает безупречно, как и без побочных побочных эффектов. Так как класс, который я написал с кодом, изменяет фактические заголовки предпочтений и стили текста сводки для всего раздела (в этом и заключался весь смысл опций, которые я добавил), я также добавил открытый конструктор классов, которые Действия, которые находятся в стеке действий под экраном стиля предпочтений, поэтому их можно обновлять одновременно. Скорее всего, я перенесу этот новый метод в класс представлений frameworks, чтобы его можно было сделать доступным для всей системы.

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

Сами переменные представления устанавливаются изначально в инициализации класса и инициализируются и определяются в View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) и View onViewCreated(View view, Bundle savedInstanceState), Сами переменные вида устанавливаются изначально в инициализации класса.

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

В действиях в стеке ниже, в моем классе PreferenceStyle, я установил пустой конструктор, который можно инициализировать в любом месте приложения.

public class DEMENTED extends SettingsPreferenceFragment implements
        Preference.OnPreferenceChangeListener, View.OnClickListener {

    public DEMENTED() {
         super();
    }

    //other code to do whatever here

В моем классе PreferenceStyle я импортировал свой класс DEMENTED, а затем установил его как переменную до onCreate(Bundle savedInstanceState):

private DEMENTED mDemented;

Затем инициализировал переменную в onCreate(Bundle savedInstanceState):

mDemented = new DEMENTED();

Вызов моему классу DEMENTED для перезагрузки его представления сделан в моем reloadView(View view) Метод, но переменная view, используемая для вызова, является переменной View, установленной непосредственно перед вызовом и установленной в null:

View tmp = null;
mDemented.reLoadView(tmp);

и мой класс DEMENTED проверяет, является ли включенный View в вызове метода нулевым, и если да, устанавливает его в локализованную переменную View, чтобы метод мог выполнять свою работу с локальными переменными:

public void reLoadView(View view) {
    if (view == null) {
        view = mView;
        Log.i(TAG, "The current View is: " + view);
    }
    //all the other good stuff here

В основном это использует ViewGroup, как определено в onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState):

    mViewGroup = parent;

и переменная вида установлена ​​в onViewCreated(View view, Bundle savedInstanceState)

    mView = view;

Надеюсь, что это кому-то поможет, потому что этот вопрос я неоднократно повторял здесь, и мне еще не удалось найти надежного решения, где бы не использовалось несколько классов, используемых в качестве утилит. Если у кого-то есть комментарии, предложения по упрощению или что-либо не стесняйтесь комментировать.

После того, как вы внесете изменения в sharedPreferences, я думаю, что вы должны просто позвонить invalidateHeaders,

Если вы ориентируетесь на API 11 и выше, вы можете использовать invalidateHeaders,

Из документов:

Звоните, когда вам нужно изменить отображаемые заголовки. Это приведет к тому, что onBuildHeaders() позже будет вызван для получения нового списка.

Другие вопросы по тегам