Search code examples
androidandroid-4.2-jelly-beanpreferencescreen

Android SwitchPreference not working correctly in 4.2.2


Any idea why having multiple SwitchPreferences in a PreferenceScreen would create an issue whereby if you select any of the boxes it causes the other boxes to change? This issue occurs when testing on a Nexus 4 running 4.2.2 but not on a Galaxy S3 running 4.0.4. Thanks for any assistance you can provide.

<?xml version="1.0" encoding="utf-8"?>

<PreferenceCategory android:title="@string/description_photo_preference">

    <SwitchPreference
            android:key="use_gallery"
            android:title="@string/title_use_gallery_preference"
            android:summaryOff="@string/summary_dont_use_gallery_as_photo_source"
            android:summaryOn="@string/summary_use_gallery_as_photo_source"
            android:defaultValue="true"
   />

    <SwitchPreference
            android:key="use_camera"
            android:title="@string/title_use_camera_preference"
            android:summaryOff="@string/summary_dont_use_camera_as_photo_source"
            android:summaryOn="@string/summary_use_camera_as_photo_source"
            android:defaultValue="true"
  />
  <SwitchPreference
            android:key="show_last_vin"
            android:title="@string/pref_string"
            android:summaryOff="@string/pref_display__false"
            android:summaryOn="@string/pref_display_true"
            android:defaultValue="true"
  />
 </PreferenceCategory>
<PreferenceCategory android:title="@string/description_photo_quality_settings">
    <ListPreference
        android:key="prefPhotoQuality"
        android:entries="@array/photo_quality_settings"
        android:summary="@string/pref_user_photo_quality_settings"
        android:entryValues="@array/photo_quality_settings_values"
        android:title="@string/description_photo_quality_settings" />
</PreferenceCategory>


Solution

  • It looks like this is a known issue as reported by this SO post.

    There is a workaround, which can be found here.

    Here's the workaround code:

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