preferencefragmentcompat activity android compatibility android-3.0-honeycomb

android - activity - ¿PreferenceFragment fue excluido intencionalmente del paquete de compatibilidad?



preference activity (8)

Estoy buscando escribir preferencias que se puedan aplicar a dispositivos 3.0 y anteriores a 3.0. Al descubrir que PreferenceActivity contiene métodos obsoletos (aunque estos se usan en el código de ejemplo adjunto), busqué PreferenceFragement y el paquete de compatibilidad para resolver mis problemas.

Sin embargo, parece que PreferenceFragment no está en el paquete de compatibilidad. ¿Alguien puede decirme si esto fue intencional? Si es así, ¿puedo apuntar fácilmente a un rango de dispositivos (es decir, <3.0 y> = 3.0) o tendré que saltar a través de los aros? Si no fue excluido intencionalmente, ¿podemos esperar una nueva versión del paquete de compatibilidad? ¿O hay otra solución alternativa que sea segura de usar?

Aclamaciones

James


Descubriendo que PreferenceActivity contiene métodos obsoletos (aunque estos se usan en el código de muestra adjunto)

Los métodos obsoletos están en desuso a partir de Android 3.0. Están perfectamente bien en todas las versiones de Android, pero la dirección es usar PreferenceFragment en Android 3.0 y superior.

¿Alguien puede decirme si esto fue intencional?

Supongo que es una cuestión de tiempo de ingeniería, pero eso es solo una suposición.

Si es así, ¿puedo apuntar fácilmente a un rango de dispositivos (es decir, <3.0 y> = 3.0) o tendré que saltar a través de los aros?

Considero que debe hacerse "fácilmente". Tenga dos implementaciones separadas de PreferenceActivity , una usando encabezados de preferencia y PreferenceFragments , la otra utilizando el enfoque original. Elija el más adecuado en el punto que necesita (por ejemplo, cuando el usuario hace clic en el elemento del menú de opciones). Aquí hay un proyecto de muestra que demuestra esto. O bien, tenga una actividad de PreferenceActivity única que maneje ambos casos, como en este proyecto de ejemplo .

Si no fue excluido intencionalmente, ¿podemos esperar una nueva versión del paquete de compatibilidad?

Descubrirás cuando el resto de nosotros lo descubramos, es decir, cuando se envíe.

¿O hay otra solución alternativa que sea segura de usar?

Véase más arriba.


Basándome en la respuesta de CommonsWare y en las observaciones de Tenacious, he creado una única solución de clase descendiente capaz de apuntar a todas las versiones actuales de la API de Android con un mínimo esfuerzo y sin duplicación de código o recursos. Por favor, consulte mi respuesta a la pregunta relacionada aquí: PreferenceActivity Android 4.0 y versiones anteriores

o en mi blog: http://www.blackmoonit.com/2012/07/all_api_prefsactivity/

Probado en dos tabletas que ejecutan 4.0.3 y 4.0.4, así como un teléfono que ejecuta 4.0.4 y 2.3.3 y también un emulador que ejecuta 1.6.


El objetivo de mi aplicación es API +14, pero debido al uso de la biblioteca de soporte para una navegación sofisticada, no pude usar android.app.Fragment y tuve que usar android.support.v4.app.Fragment , pero también necesitaba tener PreferenceFragment en su lugar sin grandes cambios al código detrás.

Así que mi solución fácil para tener ambos mundos de la biblioteca de soporte y PreferenceFragment :

private android.support.v4.app.Fragment fragment; private android.app.Fragment nativeFragment = null; private void selectItem(int position) { fragment = null; boolean useNativeFragment = false; switch (position) { case 0: fragment = new SampleSupprtFragment1(); break; case 1: fragment = new SampleSupprtFragment2(); break; case 2: nativeFragment = new SettingsFragment(); useNativeFragment = true; break; } if (useNativeFragment) { android.app.FragmentManager fragmentManager = getFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.content_frame, nativeFragment).commit(); } else { if (nativeFragment != null) { getFragmentManager().beginTransaction().remove(nativeFragment) .commit(); nativeFragment = null; } FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.content_frame, fragment).commit(); } }


En agosto de 2015, Google lanzó la nueva Preference Support Library v7 .

Ahora puede usar PreferenceFragmentCompat con cualquier Activity o AppCompatActivity

public static class PrefsFragment extends PreferenceFragmentCompat { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Load the preferences from an XML resource addPreferencesFromResource(R.xml.preferences); } }

Debes establecer preferenceTheme en tu tema:

<style name="AppTheme" parent="@style/Theme.AppCompat.Light"> ... <item name="preferenceTheme">@style/PreferenceThemeOverlay</item> </style>

De esta forma, puede personalizar el preferenceTheme para preferenceTheme un estilo a los diseños utilizados para cada tipo de preferencia sin afectar otras partes de su actividad.


La respuesta de Tenacious es correcta, pero aquí hay más detalles.

La razón por la que no puede "crear un diseño normal y vincular los componentes de vista a laspreferencias compartidas manualmente" es que hay algunas omisiones sorprendentes en la API android.preferences. PreferenceActivity y PreferenceFragment tienen acceso a los métodos críticos PreferenceManager no públicos, sin los cuales no puede implementar una IU de preferencias propia.

En particular, para construir una jerarquía de Preferencia a partir de un archivo XML, necesita usar un PreferenceManager, pero todos los constructores de PreferenceManager son privados o están ocultos. El método de vincular los oyentes de Preference onClick a su actividad también es privado del paquete.

Y no puede evitar esto colocando sigilosamente su implementación en el paquete android.preferences, porque los métodos no públicos en las API de Android se omiten en realidad en el SDK. Con un poco de creatividad que involucra la reflexión y los proxies dinámicos, aún puedes alcanzarlos. La única alternativa, como dice Tenacious, es bifurcar todo el paquete android.preference, incluyendo al menos 15 clases, 5 diseños y una cantidad similar de elementos style.xml y attrs.xml.

Entonces, para responder a la pregunta original, la razón por la que Google no incluyó PreferenceFragment en el paquete de compatibilidad es que tendrían exactamente la misma dificultad que Tenacious y yo. Incluso Google no puede retroceder en el tiempo y hacer públicos esos métodos en las plataformas antiguas (aunque espero que lo hagan en versiones futuras).


La sutil implicación de la respuesta de @CommonsWare es que su aplicación debe elegir entre la API de compatibilidad o la API de fragmento integrada (desde el SDK 11 más o menos). De hecho, eso es lo que ha hecho la recomendación "fácil". En otras palabras, si desea utilizar PreferenceFragment, su aplicación debe usar la API incorporada de fragmentos y tratar con los métodos en desuso en PreferenceActivity. Por el contrario, si es importante que su aplicación use el compat. La API te enfrentará a no tener una clase PreferenceFragment en absoluto. Por lo tanto, los dispositivos de orientación no son un problema, pero el salto al aro ocurre cuando tiene que elegir una u otra API y, por lo tanto, enviar su diseño a soluciones alternativas imprevistas. Necesito el compat. API así que voy a crear mi propia clase PreferenceFragment y ver cómo funciona eso. En el peor de los casos, crearé un diseño normal (fragmento) y vincularé los componentes de vista a las preferencias compartidas manualmente ... ugh.

EDITAR: ¿Después de probar y mirar el código en http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/preference/PreferenceFragment.java?av=h - la creación de mi propio PreferenceFragment no va a suceder. Parece que el uso liberal de package-private en PreferenceManager en lugar de ''protected'' es el principal bloqueador. Realmente no parece que haya seguridad o una buena motivación para haberlo hecho y no es bueno para las pruebas unitarias, pero bueno ... menos tipeo, supongo ...

EDITAR v2: en realidad sucedió y funcionó. Definitivamente fue un dolor de cabeza hacer que el código funcionara con el API de Compatibilidad JAR. Tuve que copiar aproximadamente el 70% del paquete com.android.preference del SDK a mi aplicación y luego luchar con el código Java de calidad mediocre en Android. Usé v14 del SDK. Habría sido mucho más fácil para un ingeniero de Goog hacer lo que hice, al contrario de lo que he escuchado decir algunos ingenieros de Android acerca de este tema.

Por cierto, ¿dije "los dispositivos de orientación no son un problema"? Es totalmente ... si usa com.android.preference, no podrá cambiar con la API de compatibilidad sin una refactorización importante. ¡Registro divertido!


Necesitaba integrar Preferencias en el diseño de la aplicación y mantener el soporte para 2.3 android. Así que todavía necesitaba PreferencesFragment.

Después de buscar, encontré android-support-v4-preferencefragment lib. Esta lib ahorra mucho tiempo para copiar y refactorizar el PreferencesFragment original como dijo Tenacious. Funciona bien y los usuarios disfrutan de las preferencias.