android - 方向更改后无法删除(子)PreferenceScreen 的子级

标签 android

我有一个 OnPreferenceClickListener,它应该从 PreferenceScreen 中删除特定的 Preference(使用键 preference_to_remove)。

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

以下代码包含两个版本,一个带有扁平的非嵌套 PreferenceScreen 和损坏的嵌套 PreferenceScreen

在屏幕方向更改后,嵌套版本无法使用键 preference_to_remove 删除 Preference 的原因是什么?除了仅使用平面 PreferenceScreensIntents 来启动新的 PreferenceScreens 作为伪子项之外,还有什么解决方案?

PS:我正在使用 PreferenceActivity 来实现 FroYo 兼容性。

如何使用 Test-App 重现

打开应用 → 点击 Flat-Button → 点击 preference_to_click 应该移除 preference_to_remove。 → 方向更改 → 单击 preference_to_click 再次删除 preference_to_remove。偏好被移除?成功!

打开 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(嵌套 PreferenceScreen)

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

最佳答案

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

我做了一些测试,我相信 PreferenceScreen 和/或用于显示嵌套 PreferenceScreenDialog 的状态以我们双方都没有预料到的方式行事。例如,当使用 PreferenceCategory 而不是 PreferenceScreen 时,不会观察到此行为。

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

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

关于android - 方向更改后无法删除(子)PreferenceScreen 的子级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12271475/

相关文章:

Android - 显示具有 sharedpreference 值的按钮

c# - 与c#计算机程序和java android应用程序的数据库连接

java - OneSignal SDK : How to open MainActivity after user taps on notification

android - Qt Android 附加安装

android - 更改列表中的第一个元素

android - 为什么我们必须在 android list 文件中声明 Activity 和服务?

android - 无用的父布局

java - 在 Android 中更快地序列化

java - 反馈电子邮件android中的设备信息

android - 如何使SearchView覆盖整个ActionBar/Toolbar