Обновите существующий элемент Preference в PreferenceActivity по возвращении с (под) PreferenceScreen - PullRequest
9 голосов
/ 13 апреля 2010

У меня есть PreferenceActivity с кучей (Sub) PreferenceScreens. Каждый такой (Sub) PreferenceScreen представляет учетную запись и имеет имя учетной записи-пользователя в качестве заголовка.

PreferenceScreen root = mgr.createPreferenceScreen(this);
for (MyAccountClass account : myAccounts) {
    final PreferenceScreen accScreen = mgr.createPreferenceScreen(this);

    accScreen.setTitle(account.getUsername());

    // add Preferences to the accScreen
    // (for instance a "change username"-preference)
    ...

    root.add(accScreen);
}

Когда пользователь вводит sub-PreferenceScreen и редактирует имя пользователя учетной записи, я хочу, чтобы внешний PreferenceScreen обновил свой PreferenceScreen-заголовок для рассматриваемой учетной записи.

Я пытался добавить ...

usernamePref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        accScreen.setTitle(newValue.toString());
        return true;
    }
});

... но accScreen.setTitle, похоже, не влияет на внешний PreferenceScreen. Я заметил, что вызов onContentChanged(); на самом деле заставляет его работать, но я понимаю, что это, вероятно, не самый предпочтительный способ сделать это.

Я подозреваю, что мне следует позвонить postInvalidate() в каком-нибудь виде, но я действительно не могу понять, какой вид и когда это сделать.

PreferenceScreen android: сводное обновление! может возникать та же проблема, что и у меня.

Любая помощь приветствуется.

Ответы [ 8 ]

16 голосов
/ 18 февраля 2011

Я нашел решение для этого. У меня есть такая иерархия, каждый из которых является PreferenceScreen:

main settings
  -> users list
    -> user1 settings
    -> user2 settings
    ...

В списке пользователей заголовок подэкрана зависит от настроек пользователя. Теперь, когда я создаю список пользователей, я сохраняю адаптер списка в своей переменной PreferenceActivity.

 PreferenceScreen usersListScreen = ...
 userScreenListAdapter = (BaseAdapter)usersListScreen.getRootAdapter();

Теперь, когда отредактированы userX-настройки, я устанавливаю заголовки в usersListScreen и после этого вызываю:

userScreenListAdapter.notifyDataSetChanged();

, который обновляет пользовательский интерфейс списка, и изменения видны.

3 голосов
/ 05 апреля 2014

notifyDataSetChanged () - правильное решение. Но я хочу добавить рекурсивный итератор для всех PreferenceScreens, поскольку у меня возникла проблема с поиском реального родителя предпочтения. Для сложной структуры предпочтений я рекомендую этот код убийцы:

private void updateAll_PrefereneScreens(PreferenceGroup group) {
    if (group instanceof PreferenceScreen) {
        BaseAdapter adapter = (BaseAdapter) ((PreferenceScreen) group).getRootAdapter();
        adapter.notifyDataSetChanged();
    }
    for (int i=0; i<group.getPreferenceCount(); i++) {
        Preference pref = group.getPreference(i);
        if (pref instanceof PreferenceGroup) {
            updateAll_PrefereneScreens((PreferenceGroup) pref);
        }
    }
}

Я вызываю его после каждого setSummary () , чтобы убедиться, что он работает правильно:

findPreference("KEY").setSummary(str);
updateAll_PrefereneScreens(getPreferenceScreen());
2 голосов
/ 01 сентября 2017

это может быть поздний ответ, но все же ... я сейчас нахожусь:)

Способ, которым я достиг этого, состоит в том, что вы можете подключить метод PreferenceFragmentCompat * onResume () его жизненного цикла и вручную обновить обязательные поля, сбросив их значения.

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

    // let's say you need to update title of the parent screen
    // when back from sub-screen(s) edition

    private int edited = -1;

    // this gets called everytime you get back to the parent screen
    @Override
    public void onResume ()
    {
        super.onResume();
        if ( edited != -1 )
        {
            PreferenceScreen root = getPreferenceScreen();
            Preference preference = root.getPreference( edited );

            if ( preference != null )
            {
                String updatedValue = getPreferenceManager()
                .getSharedPreferences()
                .getString( "your-preference-key", "your-default-value" );

                preference.setTitle( updatedValue );
            }

            edited = -1;
        }
    }

    // everytime you are about to navigate to a sub-screen 
    @Override
    public boolean onPreferenceTreeClick ( Preference preference )
    {
        // beware to save it first
        if ( preference instanceof MySubScreenPreference )
        {
            edited = preference.getOrder();
        }

        return super.onPreferenceTreeClick( preference );
    }

Как указано в документации:

onResume

Вызывается, когда фрагмент виден пользователю и активно запущен. Как правило, это связано с Activity.onResume жизненного цикла содержащей активность.

Что хорошо, так это то, что он также работает с FragmentManager ' Транзакции .

Надеюсь, это поможет, счастливого кодирования! :)

1 голос
/ 08 марта 2013

Я просто ставлю

((BaseAdapter)getPreferenceScreen().getRootAdapter()).notifyDataSetChanged();

сразу после обновления сводки моего предпочтения родителей.

1 голос
/ 23 марта 2012

PreferenceActivity#onContentChanged() обновит весь экран, при этом возникнет некоторый эффект мерцания .

Однако вы можете достичь той же цели выборочно при заданном предпочтении с помощью метода PreferenceActivity#onPreferenceTreeClick(...).

Обратите внимание, что этот метод устарел: рассмотрите возможность использования фрагментов , что, похоже, решает множество проблем с пользовательскими настройками (я еще не проверял себя). Существует пакет совместимости для старых SDK.

public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {

Log.v(TAG, "onSharedPreferenceChanged(...," + key + ")");

if (key.equals("myPref")) {
    onPreferenceTreeClick(getPreferenceScreen(), getPreferenceManager().findPreference("myPref"));
    Log.v(TAG, "Do whatever else you need...");
}

//onContentChanged();    // this could be used but occurs screen flickering
}
1 голос
/ 02 мая 2010

Я испытываю ту же проблему, но onContentChanged () не работает для меня. Моя проблема связана с настройками PreferenceScreen, которые находятся на глубине более одного уровня от корня.

Следуя вашему примеру, если вы сначала создали PreferenceScreen «Учетные записи», а затем добавили в него каждый из объектов PreferenceScreen вашей отдельной учетной записи. Как это:

Root Screen
  -> "Accounts" screen
    -> "foo@example.com" screen
      -> edit username
      -> edit password
      -> etc...
    -> "bar@example.com" screen
    -> "baz@example.com" screen
    -> etc...

Если пользователь отредактировал свое имя пользователя и нажал кнопку «Сохранить», вызов PreferenceActivity.onContentChanged (), по-видимому, влияет только на прямых потомков корневого PreferenceScreen. Заголовки и резюме экранов третьего поколения не перерисовываются, все еще отражая старые значения.

Просматривая код для onContentChanged (), кажется, что он просто заново привязывает () корневой экран к ListView ListActivity, хотя я не думаю, что последующие PreferenceScreens когда-либо привязываются к ListView (не так ли?) так что мы не можем вручную ничего связать ...

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

0 голосов
/ 25 января 2012

Источник

// Import required classes (Win: CTRL+SHIFT+O & Mac: CMD+SHIFT+O)
public class YourCustomPreference extends PreferenceActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Load the preferences from an XML resource
        addPreferencesFromResource(R.xml.preferences);
    }

    // some logic goes above, when you want to reset value and update
    // EditTextPreference value. For convenience, I am going to wrap two
    // different task in different methods
    private void resetPreferenceValue() {
        SharedPreferences sharedPref = PreferenceManager
                .getDefaultSharedPreferences(this.getApplicationContext());
        // Get preference in editor mode
        SharedPreferences.Editor prefEditor = sharedPref.edit();
        // set your default value here (could be empty as well)
        prefEditor.putString("your_edit_text_pref_key", "DEFAULT-VALUE");
        prefEditor.commit(); // finally save changes
        // Now we have updated shared preference value, but in activity it
        // still hold the old value
        this.resetElementValue();
    }

    private void resetElementValue() {
        // First get reference to edit-text view elements
        EditTextPreference myPrefText = (EditTextPreference) super
                .findPreference("your_edit_text_pref_key");
        // Now, manually update it's value to default/empty
        myPrefText.setText("DEFAULT-VALUE");
        // Now, if you click on the item, you'll see the value you've just
        // set here
    }
}
0 голосов
/ 03 января 2012

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

...