【问题标题】:Removing children of (sub-) PreferenceScreen not possible after orientation change方向更改后无法删除(子)PreferenceScreen 的子项
【发布时间】:2012-11-12 08:59:11
【问题描述】:

我有一个OnPreferenceClickListener,它应该从PreferenceScreen 中删除一个特定的Preference(带有密钥preference_to_remove)。

问题是,当preference_to_remove 不在嵌套的PreferenceScreen 内时,我的解决方案有效,但在嵌套屏幕内且屏幕方向发生变化时不起作用。在屏幕方向改变之前,嵌套屏幕也可以按预期工作。

以下代码包含两个版本,一个是平面非嵌套PreferenceScreen,另一个是破坏嵌套PreferenceScreen

在屏幕方向改变后嵌套版本无法删除Preferencepreference_to_remove 的原因是什么?除了只使用平面PreferenceScreensIntents 来开始新的PreferenceScreens 作为伪孩子之外,还有什么解决方案?

PS:我使用PreferenceActivity 是为了兼容 FroYo。

如何使用 Test-App 重现

打开应用程序→单击平面按钮→单击preference_to_click,这应该删除preference_to_remove。 → 方向更改 → 单击preference_to_click 再次删除preference_to_remove。偏好已移除?成功!

Open App → 点击 Subscreen-Button → 点击 Test → 现在重复第一次测试的步骤,但这一次preference_to_remove在方向改变后将不可移除。

Download App (Source)

pref_flat.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >

    <Preference
        android:key="preference_to_click"
        android:persistent="false"
        android:title="preference_to_click" />
    <Preference
        android:key="preference_to_remove"
        android:title="preference_to_remove" />

</PreferenceScreen>

pref_subscreen.xml(嵌套首选项屏幕)

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >

    <PreferenceScreen
        android:key="subscreen"
        android:persistent="false"
        android:title="Test" >
        <Preference
            android:key="preference_to_click"
            android:persistent="false"
            android:title="preference_to_click" />
        <Preference
            android:key="preference_to_remove"
            android:title="preference_to_remove" />
    </PreferenceScreen>

</PreferenceScreen>

PrefFlatActivity.java 和 PrefSubscreenActivity.java 的区别

1c1
< public class PrefFlatActivity extends PreferenceActivity {
---
> public class PrefSubscreenActivity extends PreferenceActivity {
5,6c5,7
<     public static final String PREFERENCE_TO_CLICK = "preference_to_click";
<     public static final String PREFERENCE_TO_REMOVE = "preference_to_remove";
---
>     private static final String PREFERENCE_TO_CLICK = PrefFlatActivity.PREFERENCE_TO_CLICK;
>     private static final String PREFERENCE_TO_REMOVE = PrefFlatActivity.PREFERENCE_TO_REMOVE;
>     private static final String PREFERENCE_SUBSCREEN = "subscreen";
15c16
<         addPreferencesFromResource(R.xml.pref_flat);
---
>         addPreferencesFromResource(R.xml.pref_subscreen);
28c29
<             PreferenceScreen screen = getPreferenceScreen();
---
>             PreferenceScreen screen = (PreferenceScreen) findPreference(PREFERENCE_SUBSCREEN);

PrefFlatActivity.java(工作)

/**
 * Works as expected. Clicking toggles the "visibility" of the PREFERENCE_TO_REMOVE Preference.
 */
public class PrefFlatActivity extends PreferenceActivity {
    /**
     * Preference keys.
     */
    public static final String PREFERENCE_TO_CLICK = "preference_to_click";
    public static final String PREFERENCE_TO_REMOVE = "preference_to_remove";

    private final String PREF_NAME = getClass().getName() + ".pref";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getPreferenceManager().setSharedPreferencesName(PREF_NAME);
        addPreferencesFromResource(R.xml.pref_flat);

        findPreference(PREFERENCE_TO_CLICK)
            .setOnPreferenceClickListener(new OnFlatClickListener());
    }

    /**
     * Removes or adds Preference with key PREFERENCE_TO_REMOVE when clicked.
     */
    private class OnFlatClickListener implements OnPreferenceClickListener {
        private Preference mRescuedPreference;

        public boolean onPreferenceClick(Preference preference) {
            PreferenceScreen screen = getPreferenceScreen();
            Preference prefToRemove = screen.findPreference(PREFERENCE_TO_REMOVE);

            Log.d("test", "Found PREFERENCE_TO_REMOVE: " + (prefToRemove != null));

            if (prefToRemove != null) {
                screen.removePreference(prefToRemove);
                mRescuedPreference = prefToRemove; // Rescue reference to re-add it later.
            }

            else {
                screen.addPreference(mRescuedPreference);
            }

            return true;
        }
    }
}

PrefSubscreenActivity.java(嵌套,方向改变后损坏)

/**
 * Broken after orientation change. Clicking does not remove/add PREFERENCE_TO_REMOVE.
 */
public class PrefSubscreenActivity extends PreferenceActivity {
    /**
     * Preference keys.
     */
    private static final String PREFERENCE_TO_CLICK = PrefFlatActivity.PREFERENCE_TO_CLICK;
    private static final String PREFERENCE_TO_REMOVE = PrefFlatActivity.PREFERENCE_TO_REMOVE;
    private static final String PREFERENCE_SUBSCREEN = "subscreen";

    private final String PREF_NAME = getClass().getName() + ".pref";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getPreferenceManager().setSharedPreferencesName(PREF_NAME);
        addPreferencesFromResource(R.xml.pref_subscreen);

        findPreference(PREFERENCE_TO_CLICK)
            .setOnPreferenceClickListener(new OnFlatClickListener());
    }

    /**
     * Removes or adds Preference with key PREFERENCE_TO_REMOVE when clicked.
     */
    private class OnFlatClickListener implements OnPreferenceClickListener {
        private Preference mRescuedPreference;

        public boolean onPreferenceClick(Preference preference) {
            PreferenceScreen screen = (PreferenceScreen) findPreference(PREFERENCE_SUBSCREEN);
            Preference prefToRemove = screen.findPreference(PREFERENCE_TO_REMOVE);

            Log.d("test", "Found PREFERENCE_TO_REMOVE: " + (prefToRemove != null));

            if (prefToRemove != null) {
                screen.removePreference(prefToRemove);
                mRescuedPreference = prefToRemove; // Rescue reference to re-add it later.
            }

            else {
                screen.addPreference(mRescuedPreference);
            }

            return true;
        }
    }
}

【问题讨论】:

    标签: android


    【解决方案1】:

    编辑:我无法按照您的要求进行此操作。我通读了Preferences 的源代码以及它们如何处理状态而没有任何运气,所以我可能遗漏了一些明显的东西(这不是经常发生的情况吗?)

    我做了一些测试,我相信PreferenceScreen 和/或Dialog 的状态用于显示嵌套的PreferenceScreen 的行为方式出乎我们的意料。例如,在使用 PreferenceCategory 而不是 PreferenceScreen 时不会观察到这种行为。

    由于这种使用Preferences 的方式已被弃用,您可以随时尝试使用片段:

    http://developer.android.com/reference/android/preference/PreferenceActivity.html

    但是,我怀疑您出于遗留原因正在避免这种情况。

    另一种选择是以编程方式创建您的Preference

    Building Preference screen in code depending on another setting

    或者,您可以自己处理配置更改:

    http://developer.android.com/reference/android/app/Activity.html#ConfigurationChanges
    https://stackoverflow.com/questions/3542333/how-to-prevent-custom-views-from-losing-state-across-screen-orientation-changes/8127813#8127813
    <activity ..
     android:configChanges="orientation|keyboardHidden" .. >
    

    希望你能尽快解决这个问题。我确信解决方案最终会出现在我们面前;不可能那么难! 希望 ;)

    原始来源(大部分)保留在下面:

        package com.example.removepref;
    
        import android.preference.Preference;
        import android.preference.Preference.OnPreferenceClickListener;
        import android.preference.PreferenceActivity;
        import android.preference.PreferenceScreen;
        import android.util.Log;
    
    
        public class PrefSubscreenActivity extends PreferenceActivity {
            /**
             * Preference keys.
             */
            private static final String PREFERENCE_TO_CLICK = PrefFlatActivity.PREFERENCE_TO_CLICK;
            private static final String PREFERENCE_TO_REMOVE = PrefFlatActivity.PREFERENCE_TO_REMOVE;
            private static final String PREFERENCE_SUBSCREEN = "subscreen";
    
            private final String PREF_NAME = getClass().getName() + ".pref";
    
            @Override
            protected void onResume() {
                super.onResume();
                getPreferenceManager().setSharedPreferencesName(PREF_NAME);
                addPreferencesFromResource(R.xml.pref_subscreen);
                findPreference(PREFERENCE_TO_CLICK).setOnPreferenceClickListener(new OnFlatClickListener());
            }
    
            /**
             * Removes or adds Preference with key PREFERENCE_TO_REMOVE when clicked.
             */
            private class OnFlatClickListener implements OnPreferenceClickListener {
                private Preference mRescuedPreference;
                private boolean mPrefToRemoveVisible = true;
                
                public boolean onPreferenceClick(Preference preference) {
                    // toggle visibility
                    mPrefToRemoveVisible = !mPrefToRemoveVisible; 
                    
                    PreferenceScreen screen = (PreferenceScreen) findPreference(PREFERENCE_SUBSCREEN);
                    Preference prefToRemove = screen.findPreference(PREFERENCE_TO_REMOVE);
                    
                    Log.d("test", "Found PREFERENCE_TO_REMOVE: " + (prefToRemove != null));
                    Log.d("test", "And noted mPrefToRemoveVisible: " + mPrefToRemoveVisible);
                    
                    //Replaced the conditional blocks:
                    if (mPrefToRemoveVisible && null == prefToRemove) {
                        boolean added = screen.addPreference(mRescuedPreference);
                        Log.d("test", "screen.addPreference(mRescuedPreference) success?" + added);
                    } else if (!mPrefToRemoveVisible && null != prefToRemove) {
                        mRescuedPreference = prefToRemove;
                        boolean removed = screen.removePreference(prefToRemove);
                        Log.d("test", "screen.removePreference(mRescuedPreference) success?" + removed);
                    }
                    
                    return true;
                }
            }
        }
    

    推荐阅读:http://developer.android.com/guide/topics/resources/runtime-changes.html

    【讨论】:

    • 很抱歉,由于以下几个原因,我不能接受这个答案:更改方向时,将显示父屏幕(不好),但 PREFERENCE_TO_REMOVE 可以切换(好)。当我将getPreferenceManager().setSharedPreferencesName(PREF_NAME); addPreferencesFromResource(R.xml.pref_subscreen); 移动到onCreate(Bundle) 时,方向更改时会显示正确的屏幕,但切换仍然失败。
    • 对不起,我的“答案”并没有真正帮助(我发誓我有一个工作样本..)我确信这是一个 state 问题,但尚未解决。我用一些变通方法更新了答案,不敢相信我是唯一的问题upvote。您是否尝试过其他方法或运气好?
    • 我目前时间很紧,所以我没有继续工作。我会及时通知您(然后可能会接受您的回答)。
    猜你喜欢
    • 1970-01-01
    • 2013-09-12
    • 2016-07-18
    • 1970-01-01
    • 1970-01-01
    • 2018-12-20
    • 1970-01-01
    • 2015-07-11
    • 1970-01-01
    相关资源
    最近更新 更多