SwitchPreferences llama varias veces al método onPreferenceChange ()
Según la guía de Android estoy intentando implementar preferencias usando Fragmentos de preferencia. En preferences.xml declaro:
<SwitchPreference android:key="enable_wifi" android:title="Enable WiFi" />
Y que en la clase Thah extends PreferenceFragment en onCreate método que hago:
- ¿Cómo usar el Porcentaje para el diseño de Android?
- Guardar el valor del elemento seleccionado mediante la preferencia compartida
- Utilizar listpreference y obtener la clave funciona, pero no hay botón ok
- Mi var pública es invisible a su primo
- Predeterminado bindPreferenceSummaryToValue se bloquea para tipos que no son de cadena
public class FragmentSettings extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); mEnableWifi = (SwitchPreference) findPreference(enable_wifi); mEnableWiFi.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { Log.i(getClass().getName(), preference.getKey() + String.valueOf(newValue)); } }
Y como resultado conseguí cuando clik en SwitchPreferene o Switch dentro de los programas de registro
enable_wifi false enable_wifi false enable_wifi true enable_wifi true
Así que por eso supongo que el oyente se llama varias veces. ¿Cómo manejarlo o arreglarlo?
- PreferenceDataStore en Android O
- Preferencias de número en la actividad de preferencias en Android
- Ejecutar un pedazo de código sólo una vez cuando se instala una aplicación
- Cómo agregar barras de herramientas a AppCompatPreferenceActivity?
- Android: ListPreference ocultar / deshabilitar valor
- Android - PreferenceActivity - Cambiar el color del texto de resumen de CheckBoxPreference
- ¿Por qué la inspección de código en SharedPreferences.getString () con el informe de valor predeterminado "puede producir NPE"?
- Preferencias de Android spinner
Se debe al error en la implementación de SwitchPreference
.
El callback onPreferenceChange
se llama:
- Primera vez con el método TwoStatePreference.onClick , que acaba de actualizar la
SharedPreference
. - Segunda vez por el estado de
Switch
widgetSwitch
. Aquí se invoca.
No puedo comentar sobre la lógica, pero por lo menos el marco debería haber tomado el cuidado de invocar onPreferenceChange
callback sólo si había un cambio en el estado. Así que la responsabilidad recae en nosotros. Utilice el método SwitchPreference.isChecked para comprobar si el estado se ha cambiado.
public boolean onPreferenceChange(Preference preference, Object newValue) { if(((SwitchPreference) preference).isChecked() != (Boolean) newValue) { // State got changed Log.i("Testing", preference.getKey() + " : " + String.valueOf(newValue)); // If you don't want to save the preference change return false from this if block. } return true; }
Aquí está el callstack para su referencia:
TwoStatePreference.onClick:
MainActivity$SettingsFragment$1.onPreferenceChange(Preference, Object) line: 45 SwitchPreference(Preference).callChangeListener(Object) line: 895 SwitchPreference(TwoStatePreference).onClick() line: 65 SwitchPreference(Preference).performClick(PreferenceScreen) line: 950 PreferenceScreen.onItemClick(AdapterView, View, int, long) line: 215 ListView(AdapterView).performItemClick(View, int, long) line: 298 ListView(AbsListView).performItemClick(View, int, long) line: 1100 AbsListView$PerformClick.run() line: 2788 AbsListView$1.run() line: 3463 Handler.handleCallback(Message) line: 730 ViewRootImpl$ViewRootHandler(Handler).dispatchMessage(Message) line: 92 Looper.loop() line: 137
Alternar conmutador de widget:
MainActivity$SettingsFragment$1.onPreferenceChange(Preference, Object) line: 45 SwitchPreference(Preference).callChangeListener(Object) line: 895 SwitchPreference$Listener.onCheckedChanged(CompoundButton, boolean) line: 47 Switch(CompoundButton).setChecked(boolean) line: 126 Switch.setChecked(boolean) line: 666 SwitchPreference.onBindView(View) line: 106
Es extraño que el código del OP carezca de la declaración de retorno para onPreferenceChange
.
Asegúrese de que está invocando return true;
Al final, por lo que la preferencia es realmente cambiado.
Si, sin embargo, el problema persiste, haga una comprobación dentro del oyente de cambio de preferencia para que no se actualice innecesariamente:
@Override public boolean onPreferenceChange(Preference preference, Object newValue) { if (preference.isEnabled() != newValue) { // Do something on normal switch return true; } else { // Preference wasn't changed, do nothing and don't update it return false; } }
Puede ser que el objeto del fragmento esté siendo guardado en memoria incluso cuando es destruido. Por lo tanto, cuando el fragmento se crea de nuevo, el oyente del fragmento anterior todavía está allí y la devolución de llamada que ve es puede ser de dos oyentes diferentes. Para confirmar que la llamada es de hecho de dos oyentes diferentes intente por favor imprimir el método toString del objeto.
@Override public boolean onPreferenceChange(Preference preference, Object newValue) { Log.i(getClass().getName(), preference.getKey() + String.valueOf(newValue)); Log.i(getClass().getName(), this.toString()); }
Si obtienes valores diferentes para el toString entonces creo que la eliminación del oyente en el fragmento onDestory podría resolver el problema para ti.
@Override public void onDestroy() { super.onDestroy(); mEnableWifi.setOnPreferenceChangeListener(null); }