从(子)PreferenceScreen 返回时更新 PreferenceActivity 中的现有首选项

发布于 2024-08-28 18:43:35 字数 1227 浏览 7 评论 0原文

我有一个 PreferenceActivity 和一堆(子)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);
}

当用户输入子 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:summary update! 可能遇到了和我一样的问题。

任何帮助表示赞赏。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

残月升风 2024-09-04 18:43:35

我找到了解决这个问题的方法。我有一个像这样的层次结构,每个都是一个 PreferenceScreen:

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

在用户列表中,子屏幕的标题取决于用户设置。现在,当我创建用户列表时,我将列表适配器存储到 PreferenceActivity 中的变量中。

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

现在,当编辑 userX-settings 时,我在 usersListScreen 中设置标题,然后调用:

userScreenListAdapter.notifyDataSetChanged();

更新列表 UI 并且更改可见。

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.

残月升风 2024-09-04 18:43:35

notifyDataSetChanged() 是正确的解决方案。但我想为所有 PreferenceScreen 添加递归迭代器,因为我在查找 Preference 的真正父级时遇到问题。对于复杂的首选项结构,我推荐这个杀手级代码:

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

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());
青春如此纠结 2024-09-04 18:43:35

这可能是一个迟到的答案,但仍然......我现在就在上面:)

我实现它的方式是,你可以连接到PreferenceFragmentCompatonResume()< /strong> 其生命周期的方法,并通过重置其值来手动更新必填字段。

注意:在这个例子中,我还跟踪编辑的首选项的索引,只是为了避免重置每个选项。

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

如文档中所指定:

恢复

当片段对用户可见并且正在主动运行时调用。这通常与包含 Activity 的生命周期的 Activity.onResume 相关。

好处是它当然也可以与 FragmentManagerTransactions 一起使用。

希望这有帮助,编码愉快! :)

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 ! :)

旧时光的容颜 2024-09-04 18:43:35

遇到同样的问题,但 onContentChanged() 对我不起作用。我的问题是 PreferenceScreens 距离根的深度超过一级。

按照您的示例,如果您首先创建了一个“帐户”PreferenceScreen,然后在其下添加了每个个人帐户 PreferenceScreen 对象。像这样:

Root Screen
  -> "Accounts" screen
    -> "[email protected]" screen
      -> edit username
      -> edit password
      -> etc...
    -> "[email protected]" screen
    -> "[email protected]" screen
    -> etc...

如果用户编辑了他们的用户名并单击“保存”,则调用 PreferenceActivity.onContentChanged() 似乎只会影响根 PreferenceScreen 的直接后代。第三代屏幕的标题和摘要没有重新绘制,仍然反映旧的价值观。

查看 onContentChanged() 的代码,看起来它只是将根 Screen 重新绑定到 ListActivity 的 ListView,尽管我不认为后续的 PreferenceScreen 会绑定到 ListView(是吗?),所以我们无法手动重新绑定任何内容...

我能想到的唯一解决方法是将子菜单创建为独立的 PreferenceActivitys 而不是 PreferenceScreens,因此我们可以有意在我们的直接祖先上调用 onContentChanged() 。但这比当前的解决方法更像是一种拼凑。有什么想法吗?

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
    -> "[email protected]" screen
      -> edit username
      -> edit password
      -> etc...
    -> "[email protected]" screen
    -> "[email protected]" 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?

生死何惧 2024-09-04 18:43:35

PreferenceActivity#onContentChanged() 将刷新整个屏幕,出现一些闪烁效果

不过,您可以使用 PreferenceActivity#onPreferenceTreeClick(...) 方法在给定的首选项上有选择地实现相同的目标。

请注意,此方法现已弃用:考虑使用 fragments 似乎可以解决问题自定义首选项有很多问题(我还没有测试过自己)。对于旧版 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
}

PreferenceActivity#onContentChanged() will refresh the whole screen, occurring some flicker effect.

However you can achieve the same goal selectively on a given preference with the PreferenceActivity#onPreferenceTreeClick(...) method.

Note that this method is now deprecated : consider using fragments that seems to solve a lot of issues with custom preferences (I've not tested myself yet). There is a compatibility package for older 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
}
晨曦÷微暖 2024-09-04 18:43:35

放置。

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

我只是在更新我的父偏好项目的摘要后立即

I'm just putting

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

right after updating the summary of my parent preference item.

情场扛把子 2024-09-04 18:43:35

来源

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

Source

// 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
    }
}
笛声青案梦长安 2024-09-04 18:43:35

这对我有用,你必须抓住 PreferenceScreen 的底层对话框并从那里设置标题,非常简单。

somePrefScreen.getDialog().setTitle("Whatever you want");

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");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文