Ciclo de vida de Android Fragment sobre cambios de orientación

Usando el paquete de compatibilidad para apuntar 2.2 usando Fragmentos.

Después de recodificar una actividad para usar fragmentos en una aplicación, no pude obtener los cambios de orientación / administración del estado funcionando, así que creé una pequeña aplicación de prueba con una sola FragmentActivity y un solo Fragment.

Los registros de los cambios de orientación son raros, con múltiples llamadas a los fragmentos OnCreateView.

Obviamente me falta algo, como separar el fragmento y volver a colocarlo en lugar de crear una nueva instancia, pero no puedo ver ninguna documentación que indique dónde me estoy equivocando.

¿Alguien puede arrojar algo de luz sobre lo que estoy haciendo mal aquí por favor? Gracias

El registro es el siguiente después de cambios de orientación.

Initial creation 12-04 11:57:15.808: D/FragmentTest.FragmentTestActivity(3143): onCreate 12-04 11:57:15.945: D/FragmentTest.FragmentOne(3143): OnCreateView 12-04 11:57:16.081: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null Orientation Change 1 12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): onSaveInstanceState 12-04 11:57:39.031: D/FragmentTest.FragmentTestActivity(3143): onCreate 12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView 12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null 12-04 11:57:39.031: D/FragmentTest.FragmentOne(3143): OnCreateView 12-04 11:57:39.167: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null Orientation Change 2 12-04 11:58:32.162: D/FragmentTest.FragmentOne(3143): onSaveInstanceState 12-04 11:58:32.162: D/FragmentTest.FragmentOne(3143): onSaveInstanceState 12-04 11:58:32.361: D/FragmentTest.FragmentTestActivity(3143): onCreate 12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView 12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null 12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView 12-04 11:58:32.361: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState not null 12-04 11:58:32.498: D/FragmentTest.FragmentOne(3143): OnCreateView 12-04 11:58:32.498: D/FragmentTest.FragmentOne(3143): OnCreateView->SavedInstanceState null 

Actividad principal (FragmentActivity)

 public class FragmentTestActivity extends FragmentActivity { /** Called when the activity is first created. */ private static final String TAG = "FragmentTest.FragmentTestActivity"; FragmentManager mFragmentManager; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Log.d(TAG, "onCreate"); mFragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction(); FragmentOne fragment = new FragmentOne(); fragmentTransaction.add(R.id.fragment_container, fragment); fragmentTransaction.commit(); } 

Y el fragmento

 public class FragmentOne extends Fragment { private static final String TAG = "FragmentTest.FragmentOne"; EditText mEditText; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d(TAG, "OnCreateView"); View v = inflater.inflate(R.layout.fragmentonelayout, container, false); // Retrieve the text editor, and restre the last saved state if needed. mEditText = (EditText)v.findViewById(R.id.editText1); if (savedInstanceState != null) { Log.d(TAG, "OnCreateView->SavedInstanceState not null"); mEditText.setText(savedInstanceState.getCharSequence("text")); } else { Log.d(TAG,"OnCreateView->SavedInstanceState null"); } return v; } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Log.d(TAG, "FragmentOne.onSaveInstanceState"); // Remember the current text, to restre if we later restart. outState.putCharSequence("text", mEditText.getText()); } 

Manifiesto

          

Estás superponiendo tus Fragmentos uno encima del otro.

Cuando se produce un cambio de configuración, el Fragmento anterior se agrega a la nueva Actividad cuando se recrea. Este es un dolor masivo en la parte posterior la mayor parte del tiempo.

Puede detener la aparición de errores utilizando el mismo Fragmento en lugar de volver a crear uno nuevo. Simplemente agrega este código:

 if (savedInstanceState == null) { // only create fragment if activity is started for the first time mFragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction(); FragmentOne fragment = new FragmentOne(); fragmentTransaction.add(R.id.fragment_container, fragment); fragmentTransaction.commit(); } else { // do nothing - fragment is recreated automatically } 

Sin embargo, ten en cuenta que los problemas se producirán si intentas acceder a Vistas de actividad desde el interior del Fragmento, ya que los ciclos de vida cambiarán sutilmente. (Obtener vistas de una Actividad principal desde un Fragmento no es fácil).

Para citar este libro , “para garantizar una experiencia de usuario coherente, Android persiste en el diseño del Fragmento y la stack posterior asociada cuando se reinicia una Actividad debido a un cambio de configuración”. (p 124)

Y la forma de abordar esto es verificar primero si la stack de Fragmentos ya se ha rellenado, y crear la nueva instancia de fragmentos solo si no:

 @Override public void onCreate(Bundle savedInstanceState) { ... FragmentOne fragment = (FragmentOne) mFragmentManager.findFragmentById(R.id.fragment_container); if (fragment == null) { FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction(); fragmentTransaction.add(R.id.fragment_container, new FragmentOne()); fragmentTransaction.commit(); } } 

El método de su actividad onCreate () se llama después de que la orientación cambie como lo ha visto. Por lo tanto, no ejecutes FragmentTransaction que agrega el Fragment después de que la orientación cambie en tu actividad.

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState==null) { //do your stuff } } 

Los fragmentos deben y no deben cambiarse.

Puede @Override FragmentActivity usando onSaveInstanceState() . Asegúrese de no llamar al super.onSaveInstanceState() en el método.

Siempre debemos tratar de evitar la excepción de nullpointer, por lo que primero debemos verificar en el método de instancia de guardado la información del paquete. para una breve explicación para verificar este enlace del blog

 public static class DetailsActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { // If the screen is now in landscape mode, we can show the // dialog in-line with the list so we don't need this activity. finish(); return; } if (savedInstanceState == null) { // During initial setup, plug in the details fragment. DetailsFragment details = new DetailsFragment(); details.setArguments(getIntent().getExtras()); getFragmentManager().beginTransaction().add(android.R.id.content, details).commit(); } } } 

En el cambio de configuración, el marco creará una nueva instancia del fragmento para usted y lo agregará a la actividad. Entonces en vez de esto:

 FragmentOne fragment = new FragmentOne(); fragmentTransaction.add(R.id.fragment_container, fragment); 

hacer esto:

 if (mFragmentManager.findFragmentByTag(FRAG1_TAG) == null) { FragmentOne fragment = new FragmentOne(); fragmentTransaction.add(R.id.fragment_container, fragment, FRAG1_TAG); } 

Tenga en cuenta que el framework agrega una nueva instancia de FragmentOne en el cambio de orientación a menos que llame a setRetainInstance (true), en cuyo caso agregará la instancia anterior de FragmentOne.

Si acaba de hacer un proyecto, entonces el gerente del proyecto dice que necesita lograr la pantalla de función de conmutación, pero no desea que la pantalla cambie el diseño de carga diferente (puede crear el diseño y el sistema de diseño de puerto).

Determinará automáticamente el estado de la pantalla, cargará el diseño correspondiente), debido a la necesidad de reiniciar la actividad o fragmento, la experiencia del usuario no es buena, no está directamente en el cambio de pantalla, me refiero? Url = YgNfP-vHy-Nuldi7YHTfNet3AtLdN-w__O3z1wLOnzr3wDjYo7X7PYdNyhw8R24ZE22xiKnydni7R0r35s2fOLcHOiLGYT9Qh_fjqtytJki & wd = & eqid = f258719e0001f24000000004585a1082

La premisa es que su diseño utilice el peso del diseño de layout_weight, de la siguiente manera:

  

Así que mi enfoque es que, al cambiar de pantalla, no es necesario cargar un nuevo diseño del archivo de vista, modifique el diseño en onConfigurationChanged pesos dynamics, los siguientes pasos: 1 primer conjunto: AndroidManifest.xml en el atributo de actividad: android: configChanges = “keyboardHidden | orientation | screenSize” Para evitar el cambio de pantalla, evite volver a cargar, a fin de poder monitorear en onConfigurationChanged 2 la actividad o fragmento de reescritura en el método onConfigurationChanged.

 @Override Public void onConfigurationChanged (Configuration newConfig) { Super.onConfigurationChanged (newConfig); SetContentView (R.layout.activity_main); if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { //On the layout / / weight adjustment LinearLayout toplayout = (LinearLayout) findViewById (R.id.toplayout); LinearLayout.LayoutParams LP = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.0f); Toplayout.setLayoutParams (LP); LinearLayout tradespace_layout = (LinearLayout) findViewById(R.id.tradespace_layout); LinearLayout.LayoutParams LP3 = new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.8f); Tradespace_layout.setLayoutParams (LP3); } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { //On the layout / / weight adjustment LinearLayout toplayout = (LinearLayout) findViewById (R.id.toplayout); LinearLayout.LayoutParams LP = new LayoutParams (LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.8f); Toplayout.setLayoutParams (LP); LinearLayout tradespace_layout = (LinearLayout) findViewById (R.id.tradespace_layout); LinearLayout.LayoutParams LP3 = new LayoutParams (LinearLayout.LayoutParams.MATCH_PARENT, 0, 2.0f); Tradespace_layout.setLayoutParams (LP3); } }