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.

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.

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.

  • Vista de lista de Android Giros de derecha / izquierda como registros de llamadas
  • DrawerLayout ListView no dibujado con GLSurfaceVer como contenido
  • Listview no actualizar en fragmento con las pestañas viewpager
  • Android: la imagen en el listview parpadea mientras llama a notifyDataSetChanged en algunos dispositivos
  • Android obtiene texto de todas las casillas marcadas en listView
  • Mostrar siempre la barra de desplazamiento para ListView
  • Android: Cómo ocultar un elemento ListView
  • Android RecyclerView con SectionIndexer
  • Error de Android - getListView () en ListFragment
  • Desmarca todas las casillas de verificación en un ListView personalizado
  • ¿Cómo usar el titular de la vista si el contenido personalizado de la fila listview es dinámico?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.