Update existing Preference-item in a PreferenceAct

2019-01-24 07:43发布

I have a PreferenceActivity with a bunch of (Sub)PreferenceScreens. Each such (Sub)PreferenceScreen represents an account and has the account-username as its title.

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

As the user enters sub-PreferenceScreen, and edits the account user-name, I want the outer PreferenceScreen to update it's PreferenceScreen-title for the account in question.

I've tried to add...

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

...but the accScreen.setTitle does not seem to take effect on the outer PreferenceScreen. I've note that calling onContentChanged(); actually makes it work, but I realize that this is probably not the preferred way of doing it.

I suspect I should call postInvalidate() on some view somewhere, but I really can't figure out on what view and when to do it.

PreferenceScreen android:summary update ! may be experiening the same problem as me.

Any help appreciated.

8条回答
ゆ 、 Hurt°
2楼-- · 2019-01-24 07:52

This works for me, you have to grab the underlying dialog of your PreferenceScreen and set the title from there, really easy.

somePrefScreen.getDialog().setTitle("Whatever you want");
查看更多
贼婆χ
3楼-- · 2019-01-24 07:53

I'm just putting

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

right after updating the summary of my parent preference item.

查看更多
混吃等死
4楼-- · 2019-01-24 08:03

notifyDataSetChanged() is right solution. But I want to add recursive iterator for all PreferenceScreens, as far as I got a problem to find real parent of a Preference. For complicated structure of Preferences I recommend this killer-code:

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

I call it after every setSummary() to ensure it works properly:

findPreference("KEY").setSummary(str);
updateAll_PrefereneScreens(getPreferenceScreen());
查看更多
疯言疯语
5楼-- · 2019-01-24 08:06

this might be a late answer but still... I'm on it right now :)

The way I achieved it, is that you can hook into the PreferenceFragmentCompat's onResume() method of its lifecycle and manually update the required field by resetting their values.

Note : in this example I also keep track of the index of the edited Preference, just to avoid reset every single ones.

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

As specified in the docs :

onResume

Called when the fragment is visible to the user and actively running. This is generally tied to Activity.onResume of the containing Activity's lifecycle.

Which is good is that it also works of course with FragmentManager's Transactions.

Hope this helps, happy coding ! :)

查看更多
我命由我不由天
6楼-- · 2019-01-24 08:10

Experiencing this same problem, but onContentChanged() isn't working for me. My problem is with PreferenceScreens that are more than one level deep from the root.

To follow your example, if you first created an "Accounts" PreferenceScreen, and then added each of your individual account PreferenceScreen objects under that. Like this:

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

If a user edited their username and clicked save, calling PreferenceActivity.onContentChanged() seems to only affect direct descendants of the root PreferenceScreen. The third-generation screens' titles and summaries do not get redrawn, still reflecting old values.

Looking through the code for onContentChanged(), it looks like it just re-bind()s the root Screen to the ListActivity's ListView, although I don't think subsequent PreferenceScreens are ever bound to a ListView (are they?), so we can't manually re-bind anything...

The only workaround I can think of would be to create the sub-menus as isolated PreferenceActivitys instead of PreferenceScreens, so we can intentionally call onContentChanged() on our direct ancestor. But that's even more of a kludge than the current workaround. Any ideas?

查看更多
霸刀☆藐视天下
7楼-- · 2019-01-24 08:11

I found a solution to this. I have a hierarchy like this, each of these is a PreferenceScreen:

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

In the users list, title of the sub-screen is dependent on the user settings. Now when I create the user list, I store the list adapter to a variable in my PreferenceActivity.

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

Now when userX-settings are edited, I set the titles in the usersListScreen and after that call:

userScreenListAdapter.notifyDataSetChanged();

which updates the list UI and the changes are visible.

查看更多
登录 后发表回答