PreferenceActivity Android 4.0 y versiones anteriores

Al intentar las diferentes actividades de preferencia en ApiDemos para Android 4.0, veo en el código que algunos métodos están obsoletos en PreferencesFromCode.java, por ejemplo.

Así que mi pregunta es: si yo uso PreferenceFragment, ¿funcionará para toda la versión o sólo 3.0 o 4.0 y arriba?

Si es así, ¿qué debo usar que funciona para 2,2 y 2,3 también?

PreferenceFragment no funcionará en 2.2 y 2.3 (sólo API nivel 11 y superior). Si desea ofrecer la mejor experiencia de usuario y seguir soportando versiones anteriores de Android, la mejor práctica aquí parece ser implementar dos clases de PreferenceActivity y decidir en tiempo de ejecución que invocar. Sin embargo, este método todavía incluye llamadas APIs obsoletas, pero no se puede evitar.

Por ejemplo, tiene un preference_headers.xml :

 <preference-headers xmlns:android="http://schemas.android.com/apk/res/android" > <header android:fragment="your.package.PrefsFragment" android:title="..."> <extra android:name="resource" android:value="preferences" /> </header> </preference-headers> 

Y un preferences.xml estándar (que no ha cambiado mucho desde niveles más bajos de la API):

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

Entonces usted necesita una implementación de PreferenceFragment :

 public static class PrefsFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); } } 

Y, por último, se necesitan dos implementaciones de PreferenceActivity , para los niveles de API que admiten o no admiten PreferenceFragments :

 public class PreferencesActivity extends PreferenceActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); addPreferencesFromResource(R.xml.other); } } 

y:

 public class OtherPreferencesActivity extends PreferenceActivity { @Override public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.preference_headers, target); } } 

En el punto en el que desea mostrar la pantalla de preferencias al usuario, usted decide cuál debe comenzar:

 if (Build.VERSION.SDK_INT < 11) { startActivity(new Intent(this, PreferencesActivity.class)); } else { startActivity(new Intent(this, OtherPreferencesActivity.class)); } 

Así que, básicamente, tiene un archivo xml por fragmento, carga cada uno de estos archivos xml manualmente para niveles de API <11, y ambas Actividades usan las mismas preferencias.

@Mef Su respuesta puede simplificarse aún más para que no necesite tanto PreferencesActivity como OtherPreferencesActivity (tener 2 PrefsActivities es un PITA).

He descubierto que puedes poner el método onBuildHeaders () en tu PreferencesActivity y ningún error será lanzado por las versiones de Android antes de v11. Tener el loadHeadersFromResource () dentro del onBuildHeaders no lanzó y la excepción en 2.3.6, pero sí en Android 1.6. Después de algunos ajustes, sin embargo, he encontrado el siguiente código funcionará en todas las versiones de modo que sólo una actividad es necesaria (simplificación en gran medida las cuestiones).

 public class PreferencesActivity extends PreferenceActivity { protected Method mLoadHeaders = null; protected Method mHasHeaders = null; /** * Checks to see if using new v11+ way of handling PrefFragments. * @return Returns false pre-v11, else checks to see if using headers. */ public boolean isNewV11Prefs() { if (mHasHeaders!=null && mLoadHeaders!=null) { try { return (Boolean)mHasHeaders.invoke(this); } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } } return false; } @Override public void onCreate(Bundle aSavedState) { //onBuildHeaders() will be called during super.onCreate() try { mLoadHeaders = getClass().getMethod("loadHeadersFromResource", int.class, List.class ); mHasHeaders = getClass().getMethod("hasHeaders"); } catch (NoSuchMethodException e) { } super.onCreate(aSavedState); if (!isNewV11Prefs()) { addPreferencesFromResource(R.xml.preferences); addPreferencesFromResource(R.xml.other); } } @Override public void onBuildHeaders(List<Header> aTarget) { try { mLoadHeaders.invoke(this,new Object[]{R.xml.pref_headers,aTarget}); } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } } } 

De esta manera solo necesitas una actividad, una entrada en tu AndroidManifest.xml y una línea cuando invocas tus preferencias:

 startActivity(new Intent(this, PreferencesActivity.class); 

UPDATE Oct 2013: Eclipse / Lint le advertirá sobre el uso del método obsoleto, pero simplemente ignore la advertencia. Estamos usando el método sólo cuando tenemos que hacerlo, que es cuando no tenemos v11 + preferencias de estilo y debemos usarlo, lo cual está bien. No se asuste con el código Deprecated cuando se ha contabilizado, Android no eliminará los métodos obsoletos en el corto plazo. Si alguna vez ocurrió, ni siquiera necesitará esta clase ya que se vería obligado a solo apuntar a nuevos dispositivos. El mecanismo Deprecated está ahí para advertirle que hay una mejor manera de manejar algo en la última versión de API, pero una vez que haya explicado, puede ignorar la advertencia desde entonces. La eliminación de todas las llamadas a métodos obsoletos sólo resultaría en obligar a que su código sólo se ejecute en dispositivos más nuevos, lo que niega la necesidad de ser compatible con versiones anteriores.

Hay un lib newish que podría ayudar.

UnifiedPreference es una biblioteca para trabajar con todas las versiones del paquete de preferencias de Android de API v4 y superior.

Problema con las respuestas anteriores es que va a apilar todas las preferencias a una sola pantalla en los dispositivos pre-Honecomb (debido a múltiples llamadas de addPreferenceFromResource() ).

Si necesita la primera pantalla como lista y luego la pantalla con preferencias (como el uso de encabezados de preferencia), debe usar Guía oficial para las preferencias compatibles

Quería señalar que si empieza en http://developer.android.com/guide/topics/ui/settings.html#PreferenceHeaders y trabaja su camino hasta la sección de "Apoyo a las versiones anteriores con los encabezados de preferencia" que será Tiene más sentido. La guía es muy servicial y funciona bien. He aquí un ejemplo explícito siguiendo su guía:

Así que comience con el archivo preferencia_header_legacy.xml para sistemas android antes de HoneyComb

 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <Preference android:title="OLD Test Title" android:summary="OLD Test Summary" > <intent android:targetPackage="example.package" android:targetClass="example.package.SettingsActivity" android:action="example.package.PREFS_ONE" /> </Preference> 

Siguiente crear archivo preferencia_header.xml para sistemas android con HoneyComb +

 <preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> <header android:fragment="example.package.SettingsFragmentOne" android:title="NEW Test Title" android:summary="NEW Test Summary" /> </preference-headers> 

A continuación, cree un archivo preferences.xml para mantener sus preferencias …

 <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > <CheckBoxPreference android:key="pref_key_auto_delete" android:summary="@string/pref_summary_auto_delete" android:title="@string/pref_title_auto_delete" android:defaultValue="false" /> </PreferenceScreen> 

A continuación, cree el archivo SettingsActivity.java

 package example.project; import java.util.List; import android.annotation.SuppressLint; import android.os.Build; import android.os.Bundle; import android.preference.PreferenceActivity; public class SettingsActivity extends PreferenceActivity{ final static String ACTION_PREFS_ONE = "example.package.PREFS_ONE"; @SuppressWarnings("deprecation") @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String action = getIntent().getAction(); if (action != null && action.equals(ACTION_PREFS_ONE)) { addPreferencesFromResource(R.xml.preferences); } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { // Load the legacy preferences headers addPreferencesFromResource(R.xml.preference_header_legacy); } } @SuppressLint("NewApi") @Override public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.preference_header, target); } } 

A continuación, cree la clase SettingsFragmentOne.java

 package example.project; import android.annotation.SuppressLint; import android.os.Bundle; import android.preference.PreferenceFragment; @SuppressLint("NewApi") public class SettingsFragmentOne extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); } } 

AndroidManifest.xml , agregó este bloque entre mis etiquetas <application>

 <activity android:label="@string/app_name" android:name="example.package.SettingsActivity" android:exported="true"> </activity> 

Y finalmente, para la etiqueta <wallpaper>

 <wallpaper xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/description" android:thumbnail="@drawable/ic_thumbnail" android:settingsActivity="example.package.SettingsActivity" /> 

Estoy utilizando esta biblioteca , que tiene un AAR en mavenCentral para que pueda incluirlo fácilmente si está usando Gradle .

compile 'com.github.machinarius:preferencefragment:0.1.1'

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.