No se puede encontrar el girador después de girar la pantalla
Estoy utilizando Fragments
para obtener un diseño con dos fragments
por lo que mi clase se extends Fragments
.
Estoy cargando un listview
en el fragment
izquierdo y en el fragment
derecho tengo otro listview
modificado. Aquí, tengo una spinner
que tengo que cambiar su color.
- Mostrar diálogo en fragmento android
- Android: patrón de ViewHolder y diferentes tipos de filas?
- Imágenes remotas en un ListView con el patrón ViewHolder
- MVVMCross Obtener SelectedItem de un MvxBindableListView
- Obtener el elemento seleccionado de customadapter listview Android
Tengo este código:
private void loadSpinner(int value) { //Not relevant code adapter = new ArrayAdapter<CharSequence>(getActivity().getApplicationContext(), android.R.layout.simple_spinner_item, data); adapter.setDropDownViewResource(R.layout.spinner); spinner.setAdapter(adapter); } @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { String value = parent.getItemAtPosition(position).toString(); ((TextView) parent.getChildAt(0)).setTextColor(getResources().getColor(R.color.black)); //Some code }
El código anterior funciona como esperado hasta que rote la pantalla de mi dispositivo. Aquí, estoy recibiendo un nullpointerexception
en ((TextView) parent.getChildAt(0)).setTextColor(getResources().getColor(R.color.black));
.
Si comento la línea anterior, ya que estoy guardando el estado antes de girar la pantalla, después de girar la pantalla, mis datos se restauran y todo funciona como se esperaba, EXCEPTO el hilandero que está en el color claro, por lo tanto, poco visible.
Entiendo que puedo crear mi propio diseño de spinner
y resolver este asunto, pero me gustaría saber cómo puedo resolver esto.
- Selector de lista de Android 4.0 + en el elemento de clic largo - Necesidad de ser persistente - No funciona
- Android lista personalizada con espacio entre los elementos
- Android: el evento onItemClick () de ListView no se llama
- Cómo actualizar lista personalizada usando baseadapter en android
- Estilos / atributos de divisor predeterminados de ListView de Android
- Disposición de la lista vacía de Android
- Haga clic en un elemento ListView cambia el estado de los elementos dentro del elemento?
- ¿Por qué aparece el teclado de Android al agregar un ListView?
Después de la rotación de la pantalla, la vista de Spinner
no tiene vistas de niños adjuntadas todavía (puede verificarlo llamando a parent.getChildCount()
), así su parent.getChildAt(0)
devuelve null, resultando en NPE
.
Explicaciones
Después de la creación de la actividad, Android muestra su contenido llamando a onMeasure()
seguido de onLayout()
para cada vista de la jerarquía de diseño.
Spinner
tendrá sus hijos vistas creadas, pobladas con datos de adaptador, y adjunto durante la llamada a onLayout()
, como se puede ver aquí .
Por lo tanto, normalmente para tu Spinner tendrás una secuencia: onMeasure
-> onLayout
-> onItemSelected
Y desde onLayout
se llama antes de onItemSelected
– todo funciona bien para usted durante el inicio de la actividad inicial.
Ahora, echemos un vistazo a lo que sucede cuando gira la pantalla:
Antes de que la actividad se destruya su onSavedInstanceState
se llama que propaga la llamada a Spinner
's onSavedInstanceState
que salvará la posición seleccionada actual.
Después de la rotación, su actividad se vuelve a crear y, a continuación, su onRestoreInstanceState
se llama.
Cuando la Actividad # onRestoreInstanceState
se llama, eventualmente llamará a Spinner's onRestoreInstanceState , que tiene el código siguiente:
SavedState ss = (SavedState) state; //...some code if (ss.selectedId >= 0) { mDataChanged = true; //...some more code }
Como se puede ver, siempre establecerá mDataChanged bandera si el estado anterior de la ruleta se guardó con onSavedInstanceState .
A continuación, onMeasure () se llama, que tiene la siguiente pieza de código:
if (mDataChanged) { handleDataChanged(); }
La implementación de handleDataChanged () eventualmente llamará a fireOnSelected (), desencadenando onItemSelected
de Spinner.
Así onItemSelected
se llama durante onMeasure
, antes onLayout
.
Y como se explicó anteriormente, Spinner
no tiene hijos antes de que su onLayout
se llame.
Espero que el problema esté claro ahora.
Solución
Para confirmar que el comportamiento y resolver NPE simplemente podría proporcionar la implementación vacía para onSavedInstanceState
/ onRestoreInstanceState
en su actividad (sin llamada a super implementación):
@Override protected void onSaveInstanceState(Bundle outState) { /* do nothing */ }
Esto evitaría la configuración de mDataChanged
y onMeasure
no activará fireOnSelected
.
Nota extra
No llamando Actividad super.
La implementación al sobreescribir onSavedInstanceState
/ onRestoreInstanceState
definitivamente no es recomendable, como mínimo no podrá guardar automáticamente estados de sus vistas internas (incluido su hilandero).
Te animo a que sólo hagas eso para verificar el comportamiento explicado arriba y para ver que NPE
ha desaparecido.
La solución preferible es definir TextView
con el color deseado para el elemento spinner en un diseño .xml y usarlo para construir ArrayAdapter
para el spinner.