¿Cómo visualizo el valor actual de una preferencia de Android en el resumen de preferencias?


457

Esto debe suceder muy a menudo.

Cuando el usuario está editando preferencias en una aplicación de Android, me gustaría que puedan ver el valor establecido actualmente de la preferencia en el Preferenceresumen.

Ejemplo: si tengo una configuración de Preferencia para "Descartar mensajes antiguos" que especifica el número de días después de los cuales los mensajes deben limpiarse. En el PreferenceActivityme gustaría que el usuario vea:

"Descartar mensajes antiguos" <- título

"Limpiar mensajes después de x días" <- resumen donde x es el valor de preferencia actual

Crédito adicional: haga que esto sea reutilizable, para que pueda aplicarlo fácilmente a todas mis preferencias, independientemente de su tipo (para que funcione con EditTextPreference, ListPreference, etc. con una cantidad mínima de codificación).

Respuestas:


151

Hay formas de hacer de esta una solución más genérica, si eso se adapta a sus necesidades.

Por ejemplo, si desea que todas las preferencias de la lista muestren su elección como resumen, podría tener esto para su onSharedPreferenceChangedimplementación:

public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
    Preference pref = findPreference(key);

    if (pref instanceof ListPreference) {
        ListPreference listPref = (ListPreference) pref;
        pref.setSummary(listPref.getEntry());
    }
}

Esto es fácilmente extensible a otras clases de preferencia.

Y mediante el uso de la funcionalidad getPreferenceCounty getPreferenceen PreferenceScreeny PreferenceCategory, podría escribir fácilmente una función genérica para recorrer el árbol de preferencias estableciendo los resúmenes de todas las preferencias de los tipos que desea para su toStringrepresentación


66
Buena solución de hecho. solo carece de una inicialización
njzk2

99
@ njzk2 todo lo que tienes que hacer es asegurarte de la actividadimplements OnSharedPreferenceChangeListener

44
NB: Hay una manera más simple, vea la respuesta de @ Robertas .
Salman von Abbas

66
En realidad, puede establecer el resumen en "%s"para ListPreferencey ListPreference.getSummary()formateará el resumen con la entrada seleccionada actual (o ""si no se seleccionó ninguna).
SOFe

findPreference (key) está en desuso, ¿hay otra forma de acceder a esto?
Nunca más el

144

Aquí está mi solución ... FWIW

package com.example.PrefTest;

import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;

public class Preferences extends PreferenceActivity implements
        OnSharedPreferenceChangeListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
        PreferenceManager.setDefaultValues(Preferences.this, R.xml.preferences,
            false);
        initSummary(getPreferenceScreen());
    }

    @Override
    protected void onResume() {
        super.onResume();
        // Set up a listener whenever a key changes
        getPreferenceScreen().getSharedPreferences()
                .registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        // Unregister the listener whenever a key changes
        getPreferenceScreen().getSharedPreferences()
                .unregisterOnSharedPreferenceChangeListener(this);
    }

    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
            String key) {
        updatePrefSummary(findPreference(key));
    }

    private void initSummary(Preference p) {
        if (p instanceof PreferenceGroup) {
            PreferenceGroup pGrp = (PreferenceGroup) p;
            for (int i = 0; i < pGrp.getPreferenceCount(); i++) {
                initSummary(pGrp.getPreference(i));
            }
        } else {
            updatePrefSummary(p);
        }
    }

    private void updatePrefSummary(Preference p) {
        if (p instanceof ListPreference) {
            ListPreference listPref = (ListPreference) p;
            p.setSummary(listPref.getEntry());
        }
        if (p instanceof EditTextPreference) {
            EditTextPreference editTextPref = (EditTextPreference) p;
            if (p.getTitle().toString().toLowerCase().contains("password"))
            {
                p.setSummary("******");
            } else {
                p.setSummary(editTextPref.getText());
            }
        }
        if (p instanceof MultiSelectListPreference) {
            EditTextPreference editTextPref = (EditTextPreference) p;
            p.setSummary(editTextPref.getText());
        }
    }
}

Esto funciona muy bien @EddieB ... excepto que tengo una pantalla de preferencias dentro de una pantalla de preferencias. ¿Alguna idea de cómo llegar a la pantalla de preferencias internas y completarlas con un resumen?
taraloca

@taraloca: cambie if (p instanceof PreferenceCategory) {PreferenceCategory pCat = (PreferenceCategory) p; a if (p instanceof PreferenceGroup) {final PreferenceGroup pCat = (PreferenceGroup) p;
Martin Ždila

este gran trabajo es lo que si EditTextPreferencees android:password="true" que muestra el valor
Chathura Wijesinghe

1
¿Cómo debo modificar el código para mostrar el resumen del archivo de recursos (xml) si no se define ningún valor (es decir if editTextPref.getText() == "")? ¿Cómo obtener un valor de resumen en updatePrefSummary? p.getSummary()y editTextPref.getSummary()devolver valores ya modificados.
LA_

Desde ambos PreferenceCategoryy PreferenceScreenheredar de PreferenceGroup, he cambiado initSummarypara manejar un PreferenceGroupen su lugar. Esto evita la necesidad de otro bucle onCreate(). Cambio de comportamiento: las PreferenceScreens anidadas ahora también se manejan de forma recursiva.
Lekensteyn

96

La documentación de Android dice que se puede usar un marcador de formato de cadena en getSummary():

Si el resumen tiene un marcador de formato de cadena (es decir, "% s" o "% 1 $ s"), el valor de entrada actual se sustituirá en su lugar.

Simplemente especificar android:summary="Clean up messages after %s days"en la declaración XML ListPreference funcionó para mí.

Nota: Esto solo funciona para ListPreference.


Alguien me corrige si me equivoco, pero la documentación de getSummary () establece que se agregó en el nivel de API 1. ¿Está implicando que el comportamiento fue diferente cuando se lanzó por primera vez?
TheIT

10
Desafortunadamente, esto solo funciona para ListPreference. Quiero el mismo comportamiento para EditTextPreference. Es sorprendente que Google no haya agregado esto para todas las Preferencias de Dialog.
Vicki

2
Además, no trabajo mientras no se haya establecido el valor: en la primera llamada de la actividad Preferencia, muestra solo% s, lo cual es realmente tonto.
Zordid

3
@ Zordid Eso se puede solucionar especificando el valor predeterminado en su xml como android:defaultValue="0"en su ListPreference. Esta es la respuesta más sensata y funciona para mí.
Mohit Singh

@Mohit Singh / @Zordid, en Lollipop API 22, el defaultValuey el %sno funcionan. En otras versiones, en general, funciona. ¿Alguna solución por favor? Estoy seguro de que no quiero escribir una clase personalizada para esto. Increíble que Google haga que las tareas más triviales sean tan dolorosas.
Narayana J

81

Si lo usas PreferenceFragment, así es como lo resolví. Se explica por sí mismo.

public static class SettingsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener {
    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      addPreferencesFromResource(R.xml.settings);
      getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    public void onResume() {
      super.onResume();
      for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); ++i) {
        Preference preference = getPreferenceScreen().getPreference(i);
        if (preference instanceof PreferenceGroup) {
          PreferenceGroup preferenceGroup = (PreferenceGroup) preference;
          for (int j = 0; j < preferenceGroup.getPreferenceCount(); ++j) {
            Preference singlePref = preferenceGroup.getPreference(j);
            updatePreference(singlePref, singlePref.getKey());
          }
        } else {
          updatePreference(preference, preference.getKey());
        }
      }
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
      updatePreference(findPreference(key), key);
    }

    private void updatePreference(Preference preference, String key) {
      if (preference == null) return;
      if (preference instanceof ListPreference) {
        ListPreference listPreference = (ListPreference) preference;
        listPreference.setSummary(listPreference.getEntry());
        return;
      }
      SharedPreferences sharedPrefs = getPreferenceManager().getSharedPreferences();
      preference.setSummary(sharedPrefs.getString(key, "Default"));
    }
  }

3
Esta solución necesita más votos ... Me molesta que los ejemplos en el sitio del desarrollador muestren que esto se está haciendo, pero lo omiten por completo.
Justin Smith el

3
Para obtener EditTextPreferences también actualizado, agregue esto a updatePreferenceCODE if (preference instanceof EditTextPreference) { EditTextPreference editTextPref = (EditTextPreference) preference; preference.setSummary(editTextPref.getText()); }gracias @EddieB
Eugene van der Merwe

66
Cuando se llama unregisterOnSharedPreferenceChangeListener?
CAMOBAP

1
findPreference(CharSequence key) This method was deprecated in API level 11. This function is not relevant for a modern fragment-based PreferenceActivity.
DSlomer64

2
@ DSlomer64 Soy muy consciente de lo que estás citando. Le está diciendo que no use PreferenceActivity.findPreference(y varios otros métodos), porque Google quiere que cambie a la técnica que se muestra en esta respuesta, que usa en su PreferenceFragment.findPreferencelugar.
Dan Hulme

33

Mi opción es extender ListPreference y está limpio:

public class ListPreferenceShowSummary extends ListPreference {

    private final static String TAG = ListPreferenceShowSummary.class.getName();

    public ListPreferenceShowSummary(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ListPreferenceShowSummary(Context context) {
        super(context);
        init();
    }

    private void init() {

        setOnPreferenceChangeListener(new OnPreferenceChangeListener() {

            @Override
            public boolean onPreferenceChange(Preference arg0, Object arg1) {
                arg0.setSummary(getEntry());
                return true;
            }
        });
    }

    @Override
    public CharSequence getSummary() {
        return super.getEntry();
    }
}

Luego agrega en su settings.xml:

<yourpackage.ListPreferenceShowSummary
    android:key="key" android:title="title"
    android:entries="@array/entries" android:entryValues="@array/values"
    android:defaultValue="first value"/>

Hice una solución basada en esto. En mi solución, tengo un método para establecer una matriz de entrada Resumen en lugar de usar las cadenas de entrada tanto en el menú como en los resúmenes. Aquí hay un problema: getEntry () devuelve el valor anterior, no el nuevo.
pzulw

1
En realidad, ¿init () es incluso necesario? Acabo de anular getSummary () y parece que funciona perfectamente.
Andy

44
¡Parece una solución mucho más fácil y limpia que la mejor votada!
muslidrikk

2
La init()función es necesaria para actualizar summarycuando el usuario cambia esa preferencia. Sin ella, se mantendrá independientemente de la entrada inicial.
anthonylawson el

23

Puede anular las clases de preferencias predeterminadas e implementar la función.

public class MyListPreference extends ListPreference  {
    public MyListPreference(Context context) { super(context); }
    public MyListPreference(Context context, AttributeSet attrs) { super(context, attrs); }
    @Override
    public void setValue(String value) {
        super.setValue(value);
        setSummary(getEntry());
    }
}

Más adelante en tu xml puedes usar preferencias personalizadas como

<your.package.name.MyListPreference 
    android:key="noteInterval"
    android:defaultValue="60"
    android:title="Notification Interval"
    android:entries="@array/noteInterval"
    android:entryValues="@array/noteIntervalValues"
    />

Excelente método simple. Solo tenga cuidado con cosas como% en la cadena getEntry ya que pueden causar problemas (o lo hicieron por mí)
Andrew

21

Después de varias horas dedicadas a resolver este problema, implementé este código:

[ACTUALIZACIÓN: el listado de la versión final]

public class MyPreferencesActivity extends PreferenceActivity {
    ...
    ListPreference m_updateList;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);

        m_updateList = (ListPreference) findPreference(getString(R.string.pref_update_interval_key));
        String currentValue = m_updateList.getValue();
        if (currentValue == null) {
            m_updateList.setValue((String)m_updateList.getEntryValues()[DEFAULT_UPDATE_TIME_INDEX]);
            currentValue = m_updateList.getValue();
        }
        updateListSummary(currentValue);    

        m_updateList.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
            @Override
            public boolean onPreferenceChange(Preference preference, Object newValue) {
                updateListSummary(newValue.toString());
                return true;
            }       
        });     
    }

    private void updateListSummary(String newValue) {
        int index = m_updateList.findIndexOfValue(newValue);
        CharSequence entry = m_updateList.getEntries()[index];
        m_updateList.setSummary(entry);
    }
}

Esa fue la única solución que me funcionó bien. Antes de intentar subclase de ListPreferences e implementar android: summary = "bla bla bla% s". Ninguno funcionó.


Tu camino es más claro y usa menos código que otros. Las mejores respuestas funcionan usando "proxy" - administrador de preferencias. No es tan claro como escuchar los cambios directos en la lista.
Paul Annekov

@Subtle Fox, solución ordenada. es curioso si hiciste 'setDefaultValue ()', entonces por qué buscar (ss == null)
Samuel

Porque setDefaultValue () no debería estar allí :) He puesto este código antes de refactorizar
Sutil Fox

20

Tal vez como ListPreference: Modifique getSummary para obtener lo que desea:

package your.package.preference;

import android.content.Context;
import android.util.AttributeSet;

public class EditTextPreference extends android.preference.EditTextPreference{
        public EditTextPreference(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }

        public EditTextPreference(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        public EditTextPreference(Context context) {
            super(context);
        }

        @Override
        public CharSequence getSummary() {
            if(super.getSummary() == null) return null;

            String summary = super.getSummary().toString();
            return String.format(summary, getText());
        }
    }

Y usa esto en tu xml:

<your.package.EditTextPreference
                android:key="pref_alpha"
                android:summary="Actual value: %s"
                android:title="Title"
                android:defaultValue="default"
                />

Entonces puede escribir un resumen en %slugar del valor real.


1
@Eruvanos @ serv-inc Al menos con una subclase de android.support.v7.preference.EditTextPreference, esto no actualiza el resumen cuando se cambia la preferencia, solo cuando se crea la actividad de preferencias. Una forma de evitar esto sin implementar OnSharedPreferenceChangeListener.onSharedPreferenceChangeden la clase de fragmento de preferencias es anular también android.support.v7.preference.EditTextPreference.setText(String text):@Override public void setText(String text) { super.setText(text); this.setSummary(this.getText()); }
PointedEars

@PointedEars: hecho. Pero esto también parece ser una copia de stackoverflow.com/a/21906829/1587329
serv-inc

18

Este es el código que necesita para establecer el resumen en el valor elegido. También establece los valores en el inicio y respeta los valores predeterminados, no solo en el cambio. Simplemente cambie "R.layout.prefs" a su archivo xml y extienda el método setSummary a sus necesidades. En realidad, solo está manejando ListPreferences, pero es fácil de personalizar para respetar otras preferencias.

package de.koem.timetunnel;

import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;

public class Prefs 
    extends PreferenceActivity 
    implements OnSharedPreferenceChangeListener {

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

       this.addPreferencesFromResource(R.layout.prefs);
       this.initSummaries(this.getPreferenceScreen());

       this.getPreferenceScreen().getSharedPreferences()
           .registerOnSharedPreferenceChangeListener(this);
    }

  /**
    * Set the summaries of all preferences
    */
  private void initSummaries(PreferenceGroup pg) {
      for (int i = 0; i < pg.getPreferenceCount(); ++i) {
          Preference p = pg.getPreference(i);
          if (p instanceof PreferenceGroup)
              this.initSummaries((PreferenceGroup) p); // recursion
          else
              this.setSummary(p);
      }
  }

  /**
    * Set the summaries of the given preference
    */
  private void setSummary(Preference pref) {
      // react on type or key
      if (pref instanceof ListPreference) {
          ListPreference listPref = (ListPreference) pref;
          pref.setSummary(listPref.getEntry());
      }
  }

  /**
    * used to change the summary of a preference
    */
  public void onSharedPreferenceChanged(SharedPreferences sp, String key) {
     Preference pref = findPreference(key);
     this.setSummary(pref);
  }

  // private static final String LOGTAG = "Prefs";
}

koem


¡Muchas gracias! Creé una clase a partir de esto, dando la identificación del recurso como un argumento para onCreate (), de esa manera fue un cambio de una línea en mis pantallas de configuración para que muestren los valores en resumen.
Asmo Soinio

2
Por cierto: tenga en cuenta que las preferencias no persistentes no se actualizarán con este sistema. Los cambios en ellos deben escucharse utilizando el setOnPreferenceChangeListener(Preference.OnPreferenceChangeListener onPreferenceChangeListener)método de preferencias individuales.
Asmo Soinio

11

En realidad, CheckBoxPreference tiene la capacidad de especificar un resumen diferente en función del valor de la casilla de verificación. Consulte los atributos android: summaryOff y android: summaryOn (así como los métodos CheckBoxPreference correspondientes).


11

Para EditTextPreference:

public class MyEditTextPreference extends EditTextPreference {
    public MyEditTextPreference(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public MyEditTextPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void setText(String text) {
        super.setText(text);
        setSummary(text);
    }
}

9

Si alguien todavía está buscando respuestas a esto, debe consultar treinta y tres respuestas.

<ListPreference
    android:key="pref_list"
    android:title="A list of preferences"
    android:summary="%s"
    android:entries="@array/pref_list_entries"
    android:entryValues="@array/pref_list_entries_values"
    android:defaultValue="0" />

Android reemplazará% s con el valor de cadena actual de la preferencia, como se muestra en el selector de ListPreference.


Trabajos. Esta es la mejor y más fácil solución hoy en día.
davidgyoung

1
Tenga en cuenta que el "% s" se puede colocar en cualquier lugar de su cadena de resumen. Y sí, ¡eso incluye cadenas de recursos!
Scott Biggs

7

Gracias por este consejo!

Tengo una pantalla de preferencia y quiero mostrar el valor de cada preferencia de lista como resumen.

Este es mi camino ahora:

public class Preferences extends PreferenceActivity implements OnSharedPreferenceChangeListener {

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
}

@Override
protected void onResume() {
    super.onResume();

    // Set up initial values for all list preferences
    Map<String, ?> sharedPreferencesMap = getPreferenceScreen().getSharedPreferences().getAll();
    Preference pref;
    ListPreference listPref;
    for (Map.Entry<String, ?> entry : sharedPreferencesMap.entrySet()) {
        pref = findPreference(entry.getKey());
        if (pref instanceof ListPreference) {
            listPref = (ListPreference) pref;
            pref.setSummary(listPref.getEntry());
        }
    }

    // Set up a listener whenever a key changes            
    getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}

@Override
protected void onPause() {
    super.onPause();

    // Unregister the listener whenever a key changes            
    getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);    
}

public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
    Preference pref = findPreference(key);

    if (pref instanceof ListPreference) {
        ListPreference listPref = (ListPreference) pref;
        pref.setSummary(listPref.getEntry());
    }
}

Esto funciona para mí, pero me pregunto cuál es la mejor solución (rendimiento, estabilidad, escalabilidad): ¿la que está mostrando Koem o esta?


6

¡Gracias, Reto, por la explicación detallada!

En caso de que esto sea de alguna ayuda para alguien, tuve que cambiar el código propuesto por Reto Meier para que funcione con el SDK para Android 1.5

@Override
protected void onResume() {
    super.onResume();

    // Setup the initial values
    mListPreference.setSummary("Current value is " + mListPreference.getEntry().toString()); 

    // Set up a listener whenever a key changes            
    ...
}

Se aplica el mismo cambio para la función de devolución de llamada onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)

Salud,

Chris


4

Resolví el problema con el siguiente descendiente de ListPreference:

public class EnumPreference extends ListPreference {

    public EnumPreference(Context aContext, AttributeSet attrs) {
        super(aContext,attrs);
    }

    @Override
    protected View onCreateView(ViewGroup parent) {
        setSummary(getEntry());
        return super.onCreateView(parent);
    }

    @Override
    protected boolean persistString(String aNewValue) {
        if (super.persistString(aNewValue)) {
            setSummary(getEntry());
            notifyChanged();
            return true;
        } else {
            return false;
        }
    }
}

Parece funcionar bien para mí en 1.6 hasta 4.0.4.


4
public class ProfileManagement extends PreferenceActivity implements
OnPreferenceChangeListener {
    EditTextPreference screenName;
    ListPreference sex;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.layout.profile_management);

            screenName = (EditTextPreference) findPreference("editTextPref");
            sex = (ListPreference) findPreference("sexSelector");

            screenName.setOnPreferenceChangeListener(this);
            sex.setOnPreferenceChangeListener(this);

    }   

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        preference.setSummary(newValue.toString());
        return true;
    }
}

4

He visto que todas las respuestas votadas muestran cómo configurar el resumen con el valor actual exacto, pero el OP también quería algo como:

"Limpiar mensajes después de x días" * <- resumen donde x es el valor de preferencia actual

Aquí está mi respuesta para lograr eso

Como dice la documentación sobre ListPreference.getSummary():

Devuelve el resumen de esta ListPreference. Si el resumen tiene un marcador de formato de cadena (es decir, "% s" o "% 1 $ s"), el valor de entrada actual se sustituirá en su lugar.

Sin embargo, probé en varios dispositivos y no parece funcionar. Con un poco de investigación, encontré una buena solución en esta respuesta . Simplemente consiste en extender todo lo Preferenceque usa y anular getSummary()para que funcione como se especifica en la documentación de Android.


1
Parece funcionar inicialmente, pero cuando elige un nuevo valor, no se actualiza automáticamente hasta que hace algo para invalidar toda la actividad y hacer que se vuelva a dibujar. Estoy en Android 4.0.4.
eidylon

Sería bueno si Google pudiera agregar una cadena de formato al objeto de preferencia.
Justin Smith el

3

Si solo desea mostrar el valor de texto sin formato de cada campo como su resumen, el siguiente código debería ser el más fácil de mantener. Solo requiere dos cambios (líneas 13 y 21, marcadas con "cambiar aquí"):

package com.my.package;

import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;

public class PreferencesActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {

    private final String[] mAutoSummaryFields = { "pref_key1", "pref_key2", "pref_key3" }; // change here
    private final int mEntryCount = mAutoSummaryFields.length;
    private Preference[] mPreferenceEntries;

    @SuppressWarnings("deprecation")
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences_file); // change here
        mPreferenceEntries = new Preference[mEntryCount];
        for (int i = 0; i < mEntryCount; i++) {
            mPreferenceEntries[i] = getPreferenceScreen().findPreference(mAutoSummaryFields[i]);
        }
    }

    @SuppressWarnings("deprecation")
    @Override
    protected void onResume() {
        super.onResume();
        for (int i = 0; i < mEntryCount; i++) {
            updateSummary(mAutoSummaryFields[i]); // initialization
        }
        getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); // register change listener
    }

    @SuppressWarnings("deprecation")
    @Override
    protected void onPause() {
        super.onPause();
        getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); // unregister change listener
    }

    private void updateSummary(String key) {
        for (int i = 0; i < mEntryCount; i++) {
            if (key.equals(mAutoSummaryFields[i])) {
                if (mPreferenceEntries[i] instanceof EditTextPreference) {
                    final EditTextPreference currentPreference = (EditTextPreference) mPreferenceEntries[i];
                    mPreferenceEntries[i].setSummary(currentPreference.getText());
                }
                else if (mPreferenceEntries[i] instanceof ListPreference) {
                    final ListPreference currentPreference = (ListPreference) mPreferenceEntries[i];
                    mPreferenceEntries[i].setSummary(currentPreference.getEntry());
                }
                break;
            }
        }
    }

    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        updateSummary(key);
    }

}

3

Aquí está mi solución:

Construya un método de tipo 'getter' de preferencia.

protected String getPreference(Preference x) {
    // http://stackoverflow.com/questions/3993982/how-to-check-type-of-variable-in-java
    if (x instanceof CheckBoxPreference)
        return "CheckBoxPreference";
    else if (x instanceof EditTextPreference)
        return "EditTextPreference";
    else if (x instanceof ListPreference)
        return "ListPreference";
    else if (x instanceof MultiSelectListPreference)
        return "MultiSelectListPreference";
    else if (x instanceof RingtonePreference)
        return "RingtonePreference";
    else if (x instanceof SwitchPreference)
        return "SwitchPreference";
    else if (x instanceof TwoStatePreference)
        return "TwoStatePreference";
    else if (x instanceof DialogPreference) // Needs to be after ListPreference
        return "DialogPreference";
    else
        return "undefined";
}

Cree un método 'setSummaryInit'.

public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
        Log.i(TAG, "+ onSharedPreferenceChanged(prefs:" + prefs + ", key:" + key + ")");
        if( key != null ) {
            updatePreference(prefs, key);
            setSummary(key);
        } else {
            Log.e(TAG, "Preference without key!");
        }
        Log.i(TAG, "- onSharedPreferenceChanged()");
    }

    protected boolean setSummary() {
        return _setSummary(null);
    }

    protected boolean setSummary(String sKey) {
        return _setSummary(sKey);
    }

    private boolean _setSummary(String sKey) {
        if (sKey == null) Log.i(TAG, "Initializing");
        else Log.i(TAG, sKey);

        // Get Preferences
        SharedPreferences sharedPrefs = PreferenceManager
                .getDefaultSharedPreferences(this);

        // Iterate through all Shared Preferences
        // http://stackoverflow.com/questions/9310479/how-to-iterate-through-all-keys-of-shared-preferences
        Map<String, ?> keys = sharedPrefs.getAll();
        for (Map.Entry<String, ?> entry : keys.entrySet()) {
            String key = entry.getKey();
            // Do work only if initializing (null) or updating specific preference key
            if ( (sKey == null) || (sKey.equals(key)) ) {
                String value = entry.getValue().toString();
                Preference pref = findPreference(key);
                String preference = getPreference(pref);
                Log.d("map values", key + " | " + value + " | " + preference);
                pref.setSummary(key + " | " + value + " | " + preference);
                if (sKey != null) return true;
            }
        }
        return false;
    }

    private void updatePreference(SharedPreferences prefs, String key) {
        Log.i(TAG, "+ updatePreference(prefs:" + prefs + ", key:" + key + ")");
        Preference pref = findPreference(key);
        String preferenceType = getPreference(pref);
        Log.i(TAG, "preferenceType = " + preferenceType);
        Log.i(TAG, "- updatePreference()");
    }

Inicializar

Cree una clase pública que PreferenceActivity e implemente OnSharedPreferenceChangeListener

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    PreferenceManager.setDefaultValues(this, R.xml.global_preferences,
    false);
    this.addPreferencesFromResource(R.xml.global_preferences);
    this.getPreferenceScreen().getSharedPreferences()
        .registerOnSharedPreferenceChangeListener(this);
}

protected void onResume() {
    super.onResume();
    setSummary();
}


3

FYI:

findPreference(CharSequence key)
This method was deprecated in API level 11. This function is not relevant
for a modern fragment-based PreferenceActivity.

Razón de más para mirar el muy hábil Answerde @ASD arriba ( fuente encontrada aquí ) que dice usar %sen android:summarycada campo preferences.xml. (Se sustituye el valor actual de preferencia %s).

ingrese la descripción de la imagen aquí

<ListPreference
 ...        
 android:summary="Length of longest word to return as match is %s"
 ...
 />

3

Dado que en la clase de preferencia androidx tiene la interfaz SummaryProvider , se puede hacer sin OnSharedPreferenceChangeListener. Se proporcionan implementaciones simples para EditTextPreference y ListPreference. Sobre la base de la respuesta de EddieB, puede verse así. Probado en androidx.preference: preferencia: 1.1.0-alpha03.

package com.example.util.timereminder.ui.prefs;

import android.os.Bundle;

import com.example.util.timereminder.R;

import androidx.preference.EditTextPreference;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroup;

/**
 * Displays different preferences.
 */
public class PrefsFragmentExample extends PreferenceFragmentCompat {

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        addPreferencesFromResource(R.xml.preferences);

        initSummary(getPreferenceScreen());
    }

    /**
     * Walks through all preferences.
     *
     * @param p The starting preference to search from.
     */
    private void initSummary(Preference p) {
        if (p instanceof PreferenceGroup) {
            PreferenceGroup pGrp = (PreferenceGroup) p;
            for (int i = 0; i < pGrp.getPreferenceCount(); i++) {
                initSummary(pGrp.getPreference(i));
            }
        } else {
            setPreferenceSummary(p);
        }
    }

    /**
     * Sets up summary providers for the preferences.
     *
     * @param p The preference to set up summary provider.
     */
    private void setPreferenceSummary(Preference p) {
        // No need to set up preference summaries for checkbox preferences because
        // they can be set up in xml using summaryOff and summary On
        if (p instanceof ListPreference) {
            p.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance());
        } else if (p instanceof EditTextPreference) {
            p.setSummaryProvider(EditTextPreference.SimpleSummaryProvider.getInstance());
        }
    }
}


2

Aquí, todos estos se cortan de la muestra Eclipse SettingsActivity . Tengo que copiar todos estos códigos demasiado para mostrar cómo estos desarrolladores de Android eligen perfectamente para un estilo de codificación más generalizado y estable.

Dejé los códigos para adaptar la PreferenceActivitytableta a una API mayor.

public class SettingsActivity extends PreferenceActivity {

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

    setupSummaryUpdatablePreferencesScreen();
}

private void setupSummaryUpdatablePreferencesScreen() {

    // In the simplified UI, fragments are not used at all and we instead
    // use the older PreferenceActivity APIs.

    // Add 'general' preferences.
    addPreferencesFromResource(R.xml.pref_general);

    // Bind the summaries of EditText/List/Dialog preferences to
    // their values. When their values change, their summaries are updated
    // to reflect the new value, per the Android Design guidelines.
    bindPreferenceSummaryToValue(findPreference("example_text"));
    bindPreferenceSummaryToValue(findPreference("example_list"));
}

/**
 * A preference value change listener that updates the preference's summary
 * to reflect its new value.
 */
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {

    private String TAG = SettingsActivity.class.getSimpleName();

    @Override
    public boolean onPreferenceChange(Preference preference, Object value) {
        String stringValue = value.toString();

        if (preference instanceof ListPreference) {
            // For list preferences, look up the correct display value in
            // the preference's 'entries' list.
            ListPreference listPreference = (ListPreference) preference;
            int index = listPreference.findIndexOfValue(stringValue);

            // Set the summary to reflect the new value.
            preference.setSummary(
                index >= 0
                ? listPreference.getEntries()[index]
                : null);
        } else {
            // For all other preferences, set the summary to the value's
            // simple string representation.
            preference.setSummary(stringValue);
        }
        Log.i(TAG, "pref changed : " + preference.getKey() + " " + value);
        return true;
    }
};

/**
 * Binds a preference's summary to its value. More specifically, when the
 * preference's value is changed, its summary (line of text below the
 * preference title) is updated to reflect the value. The summary is also
 * immediately updated upon calling this method. The exact display format is
 * dependent on the type of preference.
 *
 * @see #sBindPreferenceSummaryToValueListener
 */

private static void bindPreferenceSummaryToValue(Preference preference) {
    // Set the listener to watch for value changes.
    preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);

    // Trigger the listener immediately with the preference's
    // current value.
    sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
                                                             PreferenceManager
                                                             .getDefaultSharedPreferences(preference.getContext())
                                                             .getString(preference.getKey(), ""));
}

}

xml/pref_general.xml

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >

<!-- NOTE: EditTextPreference accepts EditText attributes. -->
<!-- NOTE: EditTextPreference's summary should be set to its value by the activity code. -->
<EditTextPreference
android:capitalize="words"
android:defaultValue="@string/pref_default_display_name"
android:inputType="textCapWords"
android:key="example_text"
android:maxLines="1"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="@string/pref_title_display_name" />

<!-- NOTE: Hide buttons to simplify the UI. Users can touch outside the dialog todismiss it.-->
<!-- NOTE: ListPreference's summary should be set to its value by the activity code. -->
<ListPreference
android:defaultValue="-1"
android:entries="@array/pref_example_list_titles"
android:entryValues="@array/pref_example_list_values"
android:key="example_list"
android:negativeButtonText="@null"
android:positiveButtonText="@null"
android:title="@string/pref_title_add_friends_to_messages" />

</PreferenceScreen>

values/strings_activity_settings.xml

<resources>
<!-- Strings related to Settings -->

<!-- Example General settings -->

<string name="pref_title_display_name">Display name</string>
<string name="pref_default_display_name">John Smith</string>

<string name="pref_title_add_friends_to_messages">Add friends to messages</string>
<string-array name="pref_example_list_titles">
<item>Always</item>
<item>When possible</item>
<item>Never</item>
</string-array>
<string-array name="pref_example_list_values">
<item>1</item>
<item>0</item>
<item>-1</item>
</string-array>
</resources>

NOTA: En realidad solo quiero comentar como "La muestra de Google para PreferenceActivity también es interesante". Pero no tengo suficientes puntos de reputación, así que por favor no me culpen.

(Perdón por el mal inglés)


2

Debe usar la función bindPreferenceSummaryToValue en el método onCreate.

Ejemplo:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Add 'general' preferences, defined in the XML file
        addPreferencesFromResource(R.xml.pref_general);

        // For all preferences, attach an OnPreferenceChangeListener so the UI summary can be
        // updated when the preference changes.
        bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_location_key)));
        bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_units_key)));
    }

Consulte la lección 3 sobre el curso de Android Udacity: https://www.udacity.com/course/viewer#!/c-ud853/l-1474559101/e-1643578599/m-1643578601


2

Para EditTextPreference :

Llegué a esta solución, por supuesto, solo si necesita una preferencia de edición de texto particular, pero podría hacer esto con cada Preferencia:

............

private static final String KEY_EDIT_TEXT_PREFERENCE2 = "on_a1";
public static  String value = "";

............

private void updatePreference(Preference preference, String key) {

            if (key.equals(KEY_EDIT_TEXT_PREFERENCE2)) {
                preference = findPreference(key);
                if (preference instanceof EditTextPreference) {
                    editTextPreference = (EditTextPreference) preference;
                    editTextPreference.setSummary(editTextPreference.getText());
                    value = editTextPreference.getText().toString();
                    return;
                }
                SharedPreferences sharedPrefs = getPreferenceManager().getSharedPreferences();
                preference.setSummary(sharedPrefs.getString(KEY_EDIT_TEXT_PREFERENCE2, ""));

            }
}

Luego en onResume ();

@Override
        public void onResume() {
            super.onResume();

            SharedPreferences etext = getPreferenceManager().getSharedPreferences();
            String str = etext.getString("value", "");
            editTextPreference = (EditTextPreference) findPreference(KEY_EDIT_TEXT_PREFERENCE2);
            editTextPreference.setText(str);
            editTextPreference.setSummary(editTextPreference.getText());

            getPreferenceScreen().getSharedPreferences()
                    .registerOnSharedPreferenceChangeListener(this);
        }

En:

@Override
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            updatePreference(findPreference(key), key);
}

2

Mi solución es crear un personalizado EditTextPreference, utilizado en XML como este:<com.example.EditTextPreference android:title="Example Title" />

EditTextPreference.java : -

package com.example;

import android.content.Context;
import android.util.AttributeSet;

public class EditTextPreference extends android.preference.EditTextPreference
{
    public EditTextPreference(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    public EditTextPreference(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public EditTextPreference(Context context)
    {
        super(context, null);
    }

    @Override
    protected void onDialogClosed(boolean positiveResult)
    {
        super.onDialogClosed(positiveResult);

        setSummary(getSummary());
    }

    @Override
    public CharSequence getSummary()
    {
        return getText();
    }
}

1

Para establecer el resumen de ListPreferencea en el valor seleccionado en un cuadro de diálogo, puede usar este código:

package yourpackage;

import android.content.Context;
import android.util.AttributeSet;

public class ListPreference extends android.preference.ListPreference {

    public ListPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    protected void onDialogClosed(boolean positiveResult) {
        super.onDialogClosed(positiveResult);
        if (positiveResult) setSummary(getEntry());
    }

    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
        super.onSetInitialValue(restoreValue, defaultValue);
        setSummary(getEntry());
    }
}

y haga referencia al yourpackage.ListPreferenceobjeto en su preferences.xmlmemoria para especificar allí su android:defaultValuecomo esto activa la llamada a onSetInitialValue().

Si lo desea, puede modificar el texto antes de llamar setSummary()a lo que sea adecuado para su aplicación.


1

Debido a que estoy usando una costumbre PreferenceDataStore, no puedo agregar un oyente a algunos, SharedPreferenceasí que tuve que escribir una solución algo hacky que escuche cada preferencia:

class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener {
    private val handler: Handler by lazy { Handler(Looper.getMainLooper()) }

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        preferenceManager.preferenceDataStore = prefs
        addPreferencesFromResource(R.xml.app_preferences)
        onPreferenceChange(preferenceScreen, null)
    }

    override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
        preference.onPreferenceChangeListener = this

        when (preference) {
            is PreferenceGroup -> for (i in 0 until preference.preferenceCount) {
                onPreferenceChange(preference.getPreference(i), null)
            }
            is ListPreference -> {
                if (preference.value == null) {
                    preference.isPersistent = false
                    preference.value = Preference::class.java.getDeclaredField("mDefaultValue")
                            .apply { isAccessible = true }
                            .get(preference).toString()
                    preference.isPersistent = true
                }

                postPreferenceUpdate(Runnable { preference.summary = preference.entry })
            }
        }
        return true
    }

    /**
     * We can't directly update the preference summary update because [onPreferenceChange]'s result
     * is used to decide whether or not to update the pref value.
     */
    private fun postPreferenceUpdate(r: Runnable) = handler.post(r)
}

1

Si está utilizando AndroidX, puede usar una personalizadaSummaryProvider . Este enfoque puede usarse para cualquiera Preference.

Ejemplo de documentación (Java):

EditTextPreference countingPreference = (EditTextPreference) findPreference("counting");

countingPreference.setSummaryProvider(new SummaryProvider<EditTextPreference>() {
    @Override
    public CharSequence provideSummary(EditTextPreference preference) {
        String text = preference.getText();
        if (TextUtils.isEmpty(text)){
            return "Not set";
        }
        return "Length of saved value: " + text.length();
    }
});

Ejemplo de documentación (Kotlin):

val countingPreference = findPreference("counting") as EditTextPreference

countingPreference.summaryProvider = SummaryProvider<EditTextPreference> { preference ->
    val text = preference.text
    if (TextUtils.isEmpty(text)) {
        "Not set"
    } else {
        "Length of saved value: " + text.length
    }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.