Android开关偏好设置在PreferenceActivity中如何同时更改

5
我在我的Android应用中使用SwitchPreference时发现了一个奇怪的问题。偏好设置中有多个SwitchPreference。
当我使用PreferenceActivity的默认布局时,一切都运行得很好。但是在我将自定义布局设置为偏好设置活动后,这些开关开始同时改变,无论你点击哪个。我正在一台基于ARM的平板电脑上测试它。同时我也在我的Android手机上测试过,结果也一样。
这是怎么回事!
以下是我偏好设置的自定义布局(`setting.xml`):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <Button
            android:id="@+id/button1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Button" />

        <Button
            android:id="@+id/button2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Button" />
    </LinearLayout>

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </ListView>

</LinearLayout>

以及PreferenceScreen

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
    <SwitchPreference
        android:key="switch1"
        android:summary="This is switch 1"
        android:title="Switch 1" />
    <SwitchPreference
        android:key="switch2"
        android:summary="This is switch 2"
        android:title="Switch 2" />
</PreferenceScreen>

在代码中,我只是设置了自定义布局。
public class SettingsActivity extends PreferenceActivity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.setting);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);

        setupSimplePreferencesScreen();
    }

    private void setupSimplePreferencesScreen() {
        addPreferencesFromResource(R.xml.pref_general);
    }
}

这是偏好设置的截图,无论点击哪个开关,这两个开关总是同时改变。 偏好设置截图

猜测是同一个ActionListener?你没有添加它。 - Daniel Bo
@DanielBo 是的,我还没有添加actionlistener,但是在设置自定义布局之前它可以正常工作。而且Android是否会为switchpreferences设置相同的默认actionlistener,这是不可能的。 - Guangming Mao
从未使用过preferenceActivity,所以我不知道:),尝试使用其他键来切换,也许id不能很好地处理switch1 switch2,因为我认为这些键用于映射如果共享首选项。 - Daniel Bo
@DanielBo 这只是一个演示。我正在开发的真正应用程序中,开关的键名完全不同。 - Guangming Mao
1个回答

7
似乎SwitchPreference的onBindView将使用其他Switch视图作为参数。
这是Google Code中Android项目中的错误问题。虽然不是完全相同的问题,但两者都描述了开关视图会根据其他开关的状态进行操作。
因此,我找到了两种解决方法:
  1. Use CheckBoxPreference if there are more than one boolean preference in your screen.
  2. Use this workaround

    public class CustomSwitchPreference extends SwitchPreference {
    
        /**
         * Construct a new SwitchPreference with the given style options.
         *
         * @param context The Context that will style this preference
         * @param attrs Style attributes that differ from the default
         * @param defStyle Theme attribute defining the default style options
         */
        public CustomSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        /**
         * Construct a new SwitchPreference with the given style options.
         *
         * @param context The Context that will style this preference
         * @param attrs Style attributes that differ from the default
         */
        public CustomSwitchPreference(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        /**
         * Construct a new SwitchPreference with default style options.
         *
         * @param context The Context that will style this preference
         */
        public CustomSwitchPreference(Context context) {
            super(context, null);
        }
    
        @Override
        protected void onBindView(View view) {
            // Clean listener before invoke SwitchPreference.onBindView
            ViewGroup viewGroup= (ViewGroup)view;
            clearListenerInViewGroup(viewGroup);
            super.onBindView(view);
        }
    
        /**
         * Clear listener in Switch for specify ViewGroup.
         *
         * @param viewGroup The ViewGroup that will need to clear the listener.
         */
        private void clearListenerInViewGroup(ViewGroup viewGroup) {
            if (null == viewGroup) {
                return;
            }
    
            int count = viewGroup.getChildCount();
            for(int n = 0; n < count; ++n) {
                View childView = viewGroup.getChildAt(n);
                if(childView instanceof Switch) {
                    final Switch switchView = (Switch) childView;
                    switchView.setOnCheckedChangeListener(null);
                    return;
                } else if (childView instanceof ViewGroup){
                    ViewGroup childGroup = (ViewGroup)childView;
                    clearListenerInViewGroup(childGroup);
                }
            }
        }
    
    }
    

我已经测试了这两个解决方案。它们都有效。


太棒了!谢谢@Garnel。我刚刚实现了CustomSwitchPreference,它对我非常有效。 - Zorfling
救了我的一天!我只是使用了CheckBoxPreference。 - akohout

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接