2011-06-24 9 views
21

Tengo una actividad de preferencia que tiene un language como ListPreference que muestra la lista de idiomas disponibles. Puedo completar la lista cuando se llame a onCreate, pero deseo completar la lista cuando el usuario haga clic en ella.Cómo llenar ListPreference dinámicamente cuando onPreferenceClick se desencadena?

this is the java code:

public class SettingsActivity extends PreferenceActivity implements OnPreferenceClickListener { 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     try { 
      addPreferencesFromResource(R.xml.settings); 
     } catch (Exception e) { 

     } 

    } 

    @Override 
    public boolean onPreferenceClick(Preference preference) { 

     if((preference instanceof ListPreference) && (preference.getKey().equals("language"))){ 
      ListPreference lp = (ListPreference)preference; 
      CharSequence[] entries = { "English", "French" }; 
      CharSequence[] entryValues = {"1" , "2"}; 
      lp.setEntries(entries); 
      lp.setDefaultValue("1"); 
      lp.setEntryValues(entryValues); 
      return true; 
     } 
     return false; 

    } 
} 

y este es el settings.xml (preferencia):

<?xml version="1.0" encoding="utf-8"?> 
<PreferenceScreen 
    xmlns:android="http://schemas.android.com/apk/res/android"> 
    <PreferenceCategory android:title="General Settings"> 
     <CheckBoxPreference android:key="enabled" android:title="Application Status" android:summary="Enable or disable the application" /> 
     <ListPreference 
     android:key="language" 
     android:title="Language" 
     android:dialogTitle="Application language" 
     android:summary="Select the Application language" 
     /> 
    </PreferenceCategory> 
</PreferenceScreen> 

busqué pero no encontré ningún resultado! Se produce una excepción cada vez que hago clic en esa lista.

Respuesta

36

que está recibiendo la excepción porque su objeto ListPreference no se ha inicializado totalmente - que sea necesario establecer entries y entryValues atributos en el código XML o hacerlo mediante programación en onCreate().

Si lo que desea es poder cambiar los elementos de la lista dinámicamente después de que se haya inicializado el objeto ListPreference inicial, deberá adjuntar el OnPreferenceClickListener directamente al objeto ListPreference. Use la clave que ha especificado en el XML para obtener un control de la preferencia.

Dado que el código para rellenar los entries y entryValues matrices tendrán que funcionar tanto en onCreate() y en onPreferenceClick, que tiene sentido para extraerlo a un método separado - setListPreferenceData() con el fin de evitar la duplicación.

public class SettingsActivity extends PreferenceActivity { 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     try { 
      addPreferencesFromResource(R.xml.settings); 
     } catch (Exception e) { 

     } 

     final ListPreference listPreference = (ListPreference) findPreference("language"); 

     // THIS IS REQUIRED IF YOU DON'T HAVE 'entries' and 'entryValues' in your XML 
     setListPreferenceData(listPreference); 

     listPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() { 
      @Override 
      public boolean onPreferenceClick(Preference preference) { 

       setListPreferenceData(listPreference); 
       return false; 
      } 
     }); 
    } 

    protected static void setListPreferenceData(ListPreference lp) { 
      CharSequence[] entries = { "English", "French" }; 
      CharSequence[] entryValues = {"1" , "2"}; 
      lp.setEntries(entries); 
      lp.setDefaultValue("1"); 
      lp.setEntryValues(entryValues); 
    } 
} 
+2

Esta respuesta funciona, pero es un poco problemático si dejas que setListPreferenceData se ejecute solo enHaga clic (y no enCerencia). Eso es porque si el método setListPreferenceData toma más de una fracción de de un segundo, entonces se muestra la lista predeterminada antes de establecer los datos, y el usuario está forzado a cancelar y luego vuelve a abrir la preferencia. ¿Hay una forma de actualizar la listaPreferencia que ya se está mostrando después de que setListPreferenceData haya finalizado? – Malabarba

+3

Si necesita un comportamiento personalizado, su mejor opción sería ampliar 'ListPreference' o' Preference'. Una solución puramente "social" sería establecer el valor del elemento de lista predeterminado en algo como ccpizza

+1

Sí, tuve que extender la preferencia de la lista por mi cuenta. Pero no fue tan malo. onCreate fue el único método que necesitó sobrecargar. – Malabarba

2

Usando PreferenceFragment & JAVA clave conjunto en lugar de PreferenceActivity & XML como se muestra en https://stackoverflow.com/a/13828912/1815624, que esta respuesta se basa en:

Si lo que desea es ser capaz de cambiar los elementos en la lista de forma dinámica después de que el objeto inicial ListPreference se haya inicializado, entonces deberá adjuntar el OnPreferenceClickListener directamente al objeto ListPreference. Use la clave que tiene especificada en la fuente JAVA (como CUSTOM_LIST) para obtener un control de la preferencia.

Dado que el código para rellenar los entries y entryValues matrices tendrán que funcionar tanto en onCreate() y en onPreferenceClick, que tiene sentido para extraerlo a un método separado - setListPreferenceData() con el fin de evitar la duplicación.

/** 
* This fragment shows data and sync preferences only. It is used when the 
* activity is showing a two-pane settings UI. 
*/ 
@TargetApi(Build.VERSION_CODES.HONEYCOMB) 
public static class myCustomPreferenceFragment extends PreferenceFragment { 

    final private String CUSTOM_LIST= "custom_list"; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     addPreferencesFromResource(R.xml.pref_custom_frag); 

     PreferenceCategory targetCategory = (PreferenceCategory) findPreference("CUSTOM_FRAG"); 

     final ListPreference lp = setListPreferenceData((ListPreference) findPreference(CUSTOM_LIST), getActivity()); 

     lp.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { 
      @Override 
      public boolean onPreferenceClick(Preference preference) { 

       setListPreferenceData(lp, getActivity()); 
       return false; 
      } 
     }); 
     setHasOptionsMenu(true); 
     targetCategory.addPreference(lp); 

     bindPreferenceSummaryToValue(targetCategory); 
     bindPreferenceSummaryToValue(lp); 
    } 

    protected ListPreference setListPreferenceData(ListPreference lp, Activity mActivity) { 
     CharSequence[] entries = { "One", "Two", "Three" }; 
     CharSequence[] entryValues = { "1", "2", "3" }; 
     if(lp == null) 
      lp = new ListPreference(mActivity); 
     lp.setEntries(entries); 
     lp.setDefaultValue("1"); 
     lp.setEntryValues(entryValues); 
     lp.setTitle("Number Of blahs"); 
     lp.setSummary(lp.getEntry()); 
     lp.setDialogTitle("Number of Blah objects"); 
     lp.setKey(CUSTOM_LIST); 
     return lp; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     int id = item.getItemId(); 
     if (id == android.R.id.home) { 
      startActivity(new Intent(getActivity(), SettingsActivity.class)); 
      return true; 
     } 
     return super.onOptionsItemSelected(item); 
    } 
} 

diseño XML:

<?xml version="1.0" encoding="utf-8"?> 
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> 
    <PreferenceCategory 
     android:key="CUSTOM_FRAG" 
     android:title="Some Options"> 

    </PreferenceCategory> 
</PreferenceScreen> 
0

me resolvió el problema de mi extender el ListPreference. Fue muy simple.

public class DListPref extends ListPreference 
{ 
    public interface LoadingListener 
    { 
     void setData(ListPreference lp); 
    } 

    LoadingListener TheLL; 

    public void setLoadingListener(LoadingListener l) 
    { 
     TheLL = l; 
    } 

    @Override 
    protected void onPrepareDialogBuilder(AlertDialog.Builder builder) 
    { 
     if(TheLL!=null) 
     { 
      TheLL.setData(this); 
     } 
     super.onPrepareDialogBuilder(builder); 
    } 

    //Do not mind the rest of this class, as they are auto-generated boilerplate code. 
    public DListPref(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) 
    { 
     super(context, attrs, defStyleAttr, defStyleRes); 
    } 

    public DListPref(Context context, AttributeSet attrs, int defStyleAttr) 
    { 
     super(context, attrs, defStyleAttr); 
    } 

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

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

Y luego acabo de cambiar el nombre a mi clase en el XML.

<my.company.DListPref 
    android:defaultValue="-1" 
    android:key="damn" 
    android:title="vegetables"/> 

Y luego simplemente lo hice en el onCreate.

 DListPref lp = (DListPref) findPreference("damn"); 

     lp.setLoadingListener(new DListPref.LoadingListener() 
     { 
      @Override 
      public void setData(ListPreference lp) 
      { 
       lp.setEntries(new String[]{"doge", "wow"}); 
       lp.setEntryValues(new String[] {"1", "2"}); 
       lp.setDefaultValue("1"); 
      } 
     }); 

Funcionó de inmediato. En realidad, nunca esperé que se hiciera tan fácilmente.

Cuestiones relacionadas