studio screensize rotate how configchanges change android android-fragments android-activity rotation

screensize - on rotate android



ComprensiĆ³n adicional setRetainInstance(true) (2)

¿Qué ocurre exactamente cuando llamas a setRetainInstance(true) en un Fragment ? La documentación es prácticamente inexistente y esta parece ser una función muy importante. Específicamente, quiero saber cuánto de esta secuencia (que inventé) es verdadera:

  1. El usuario gira el dispositivo.
  2. El fragmento se separa de la Activity y se llama Fragment.onDetach() .
  3. La actividad se destruye; Activity.onDestroy() se llama.
  4. El objeto Activity java se elimina (cuando es posible, por el GC).
  5. Se crea un nuevo objeto Activity ; su constructor, y onCreate() son llamados.
  6. En Activity.onCreate() tenemos setContentView(...) que establece un diseño que contiene un fragmento, o usamos FragmentTransaction para agregar un fragmento.
  7. Realmente no estoy seguro de esto, pero supongo que Android es lo suficientemente inteligente como para encontrar el fragmento anterior, y llama a Fragment.onAttach() para volver a conectarlo a la nueva Activity
  8. Siguiente (¿o antes? ¿Quién sabe? Activity.onResume() Se llama Activity.onResume() .

Entonces, ¿es correcto? ¿Es Android lo suficientemente inteligente como para encontrar el fragmento anterior, incluso si utilizo FragmentTransaction.add(new MyFragment(), ...) explícitamente la primera vez? Y si es así, ¿cómo evito agregar otro fragmento en onCreate() ? ¿Tengo que hacer algo como esto ?:

if (getSupportFragmentManager().findFragmentByTag("foo") == null) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.add(new FooFragment(), "foo").commit(); }


Ok, tal vez fui un poco duro con la documentación de Android porque tiene cierta información útil, pero lamentablemente nada de eso está vinculado desde setRetainInstance() . De la página sobre fragmentos

Nota: Cada fragmento requiere un identificador único que el sistema puede usar para restaurar el fragmento si la actividad se reinicia (y que puede usar para capturar el fragmento para realizar transacciones, como eliminarlo). Hay tres formas de proporcionar una identificación para un fragmento:

  • Proporcione el atributo android: id con una ID única.
  • Proporcione el atributo android: tag con una cadena única.
  • Si no proporciona ninguno de los dos anteriores, el sistema usa el ID de la vista de contenedor.

Esto implica fuertemente que si setContentView(R.layout.whatever) en Activity.onCreated() y ese diseño contiene un fragmento con setRetainInstance(true) , cuando se recrea la actividad se buscará nuevamente usando su identificación o etiqueta .

En segundo lugar, para los fragmentos sin UI, indica

Para agregar un fragmento sin una IU, agregue el fragmento de la actividad usando agregar (Fragmento, Cadena) (proporcionando una "etiqueta" de cadena única para el fragmento, en lugar de una ID de vista). Esto agrega el fragmento, pero, como no está asociado a una vista en el diseño de la actividad, no recibe una llamada a onCreateView (). Entonces no necesitas implementar ese método.

Y los documentos se vinculan a un muy buen ejemplo: FragmentRetainInstance.java que he reproducido a continuación para su conveniencia. Hace exactamente lo que especulé fue la respuesta en mi pregunta ( if (...findFragmentByTag() == null) { ... ).

Finalmente, creé mi propia actividad de prueba para ver exactamente qué funciones se llaman. Emite esto, cuando comienzas en retrato y giras al paisaje. El código está abajo.

(Esto se edita un poco para que sea más fácil de leer).

TestActivity@415a4a30: this() TestActivity@415a4a30: onCreate() TestActivity@415a4a30: Existing fragment not found. TestFragment{41583008}: this() TestFragment{41583008} TestFragment{41583008}: onAttach(TestActivity@415a4a30) TestFragment{41583008}: onCreate() TestFragment{41583008}: onCreateView() TestFragment{41583008}: onActivityCreated() TestActivity@415a4a30: onStart() TestFragment{41583008}: onStart() TestActivity@415a4a30: onResume() TestFragment{41583008}: onResume() <rotate device> TestFragment{41583008}: onPause() TestActivity@415a4a30: onPause() TestFragment{41583008}: onStop() TestActivity@415a4a30: onStop() TestFragment{41583008}: onDestroyView() TestFragment{41583008}: onDetach() TestActivity@415a4a30: onDestroy() TestActivity@415a3380: this() TestFragment{41583008}: onAttach(TestActivity@415a3380) TestActivity@415a3380: onCreate() TestActivity@415a3380: Existing fragment found. TestFragment{41583008}: onCreateView() TestFragment{41583008}: onActivityCreated() TestActivity@415a3380: onStart() TestFragment{41583008}: onStart() TestActivity@415a3380: onResume() TestFragment{41583008}: onResume()

Tenga en cuenta que la documentación de Android es incorrecta: el fragmento sin interfaz de usuario recibe una llamada a onCreateView() pero es libre de devolver null .

Código fuente para TestActivity / TestFragment

import android.app.Activity; import android.app.Fragment; import android.app.FragmentTransaction; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.concentriclivers.ss.R; // An activity for understanding Android lifecycle events. public class TestActivity extends Activity { private static final String TAG = TestActivity.class.getSimpleName(); public TestActivity() { super(); Log.d(TAG, this + ": this()"); } protected void finalize() throws Throwable { super.finalize(); Log.d(TAG, this + ": finalize()"); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, this + ": onCreate()"); TextView tv = new TextView(this); tv.setText("Hello world"); setContentView(tv); if (getFragmentManager().findFragmentByTag("test_fragment") == null) { Log.d(TAG, this + ": Existing fragment not found."); FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.add(new TestFragment(), "test_fragment").commit(); } else { Log.d(TAG, this + ": Existing fragment found."); } } @Override public void onStart() { super.onStart(); Log.d(TAG, this + ": onStart()"); } @Override public void onResume() { super.onResume(); Log.d(TAG, this + ": onResume()"); } @Override public void onPause() { super.onPause(); Log.d(TAG, this + ": onPause()"); } @Override public void onStop() { super.onStop(); Log.d(TAG, this + ": onStop()"); } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, this + ": onDestroy()"); } public static class TestFragment extends Fragment { private static final String TAG = TestFragment.class.getSimpleName(); public TestFragment() { super(); Log.d(TAG, this + ": this() " + this); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, this + ": onCreate()"); setRetainInstance(true); } @Override public void onAttach(final Activity activity) { super.onAttach(activity); Log.d(TAG, this + ": onAttach(" + activity + ")"); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Log.d(TAG, this + ": onActivityCreated()"); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d(TAG, this + ": onCreateView()"); return null; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); Log.d(TAG, this + ": onViewCreated()"); } @Override public void onDestroyView() { super.onDestroyView(); Log.d(TAG, this + ": onDestroyView()"); } @Override public void onDetach() { super.onDetach(); Log.d(TAG, this + ": onDetach()"); } @Override public void onStart() { super.onStart(); Log.d(TAG, this + ": onStart()"); } @Override public void onResume() { super.onResume(); Log.d(TAG, this + ": onResume()"); } @Override public void onPause() { super.onPause(); Log.d(TAG, this + ": onPause()"); } @Override public void onStop() { super.onStop(); Log.d(TAG, this + ": onStop()"); } @Override public void onDestroy() { super.onDestroy(); Log.d(TAG, this + ": onDestroy()"); } } }

Código fuente para FragmentRetainInstance.java (a partir de API 16):

/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.apis.app; import com.example.android.apis.R; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ProgressBar; /** * This example shows how you can use a Fragment to easily propagate state * (such as threads) across activity instances when an activity needs to be * restarted due to, for example, a configuration change. This is a lot * easier than using the raw Activity.onRetainNonConfiguratinInstance() API. */ public class FragmentRetainInstance extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // First time init, create the UI. if (savedInstanceState == null) { getFragmentManager().beginTransaction().add(android.R.id.content, new UiFragment()).commit(); } } /** * This is a fragment showing UI that will be updated from work done * in the retained fragment. */ public static class UiFragment extends Fragment { RetainedFragment mWorkFragment; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_retain_instance, container, false); // Watch for button clicks. Button button = (Button)v.findViewById(R.id.restart); button.setOnClickListener(new OnClickListener() { public void onClick(View v) { mWorkFragment.restart(); } }); return v; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); FragmentManager fm = getFragmentManager(); // Check to see if we have retained the worker fragment. mWorkFragment = (RetainedFragment)fm.findFragmentByTag("work"); // If not retained (or first time running), we need to create it. if (mWorkFragment == null) { mWorkFragment = new RetainedFragment(); // Tell it who it is working with. mWorkFragment.setTargetFragment(this, 0); fm.beginTransaction().add(mWorkFragment, "work").commit(); } } } /** * This is the Fragment implementation that will be retained across * activity instances. It represents some ongoing work, here a thread * we have that sits around incrementing a progress indicator. */ public static class RetainedFragment extends Fragment { ProgressBar mProgressBar; int mPosition; boolean mReady = false; boolean mQuiting = false; /** * This is the thread that will do our work. It sits in a loop running * the progress up until it has reached the top, then stops and waits. */ final Thread mThread = new Thread() { @Override public void run() { // We''ll figure the real value out later. int max = 10000; // This thread runs almost forever. while (true) { // Update our shared state with the UI. synchronized (this) { // Our thread is stopped if the UI is not ready // or it has completed its work. while (!mReady || mPosition >= max) { if (mQuiting) { return; } try { wait(); } catch (InterruptedException e) { } } // Now update the progress. Note it is important that // we touch the progress bar with the lock held, so it // doesn''t disappear on us. mPosition++; max = mProgressBar.getMax(); mProgressBar.setProgress(mPosition); } // Normally we would be doing some work, but put a kludge // here to pretend like we are. synchronized (this) { try { wait(50); } catch (InterruptedException e) { } } } } }; /** * Fragment initialization. We way we want to be retained and * start our thread. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Tell the framework to try to keep this fragment around // during a configuration change. setRetainInstance(true); // Start up the worker thread. mThread.start(); } /** * This is called when the Fragment''s Activity is ready to go, after * its content view has been installed; it is called both after * the initial fragment creation and after the fragment is re-attached * to a new activity. */ @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Retrieve the progress bar from the target''s view hierarchy. mProgressBar = (ProgressBar)getTargetFragment().getView().findViewById( R.id.progress_horizontal); // We are ready for our thread to go. synchronized (mThread) { mReady = true; mThread.notify(); } } /** * This is called when the fragment is going away. It is NOT called * when the fragment is being propagated between activity instances. */ @Override public void onDestroy() { // Make the thread go away. synchronized (mThread) { mReady = false; mQuiting = true; mThread.notify(); } super.onDestroy(); } /** * This is called right before the fragment is detached from its * current activity instance. */ @Override public void onDetach() { // This fragment is being detached from its activity. We need // to make sure its thread is not going to touch any activity // state after returning from this function. synchronized (mThread) { mProgressBar = null; mReady = false; mThread.notify(); } super.onDetach(); } /** * API for our UI to restart the progress thread. */ public void restart() { synchronized (mThread) { mPosition = 0; mThread.notify(); } } } }


setRetainInstance() en la clase Fragment es un reemplazo inteligente para onRetainCustomNonConfigurationInstance() de la clase Activity , y más.

Claramente declarado en la documentación .

Aquí está el registro de lo que sucede (un fragmento de la interfaz de usuario agrega a demanda y luego un cambio de configuración):

Default setRetainInstance(false)

09-29 13:23:04.771: DEBUG/szipinf(4790): Initializing inflate state 09-29 13:23:04.801: INFO/TESTING - MYACTIVITY(4790): Instantiated - com.example.MyActivity@405196b0 09-29 13:23:04.851: DEBUG/dalvikvm(4790): GC_EXTERNAL_ALLOC freed 49K, 51% free 2686K/5379K, external 0K/0K, paused 45ms 09-29 13:23:04.881: INFO/TESTING - MYACTIVITY(4790): onCreate - com.example.MyActivity@405196b0 09-29 13:23:04.881: INFO/TESTING - MYACTIVITY(4790): onStart - com.example.MyActivity@405196b0 09-29 13:23:04.881: INFO/TESTING - MYACTIVITY(4790): onResume - com.example.MyActivity@405196b0 09-29 13:23:04.891: INFO/TESTING - MYACTIVITY(4790): onAttachedToWindow - com.example.MyActivity@405196b0 09-29 13:23:10.381: DEBUG/dalvikvm(4457): GC_EXPLICIT freed 8K, 51% free 2681K/5379K, external 0K/0K, paused 38ms 09-29 13:23:11.901: INFO/TESTING - MYFRAGMENT(4790): Instantiated - MyFragment{40530610} 09-29 13:23:11.911: INFO/TESTING - MYFRAGMENT(4790): onAttach - MyFragment{40530610 #0 MyFragment} 09-29 13:23:11.911: INFO/TESTING - MYACTIVITY(4790): onAttachFragment - com.example.MyActivity@405196b0 09-29 13:23:11.911: INFO/TESTING - MYFRAGMENT(4790): onCreate - MyFragment{40530610 #0 MyFragment} 09-29 13:23:11.911: INFO/TESTING - MYFRAGMENT(4790): onCreateView - MyFragment{40530610 #0 MyFragment} 09-29 13:23:11.921: INFO/TESTING - MYFRAGMENT(4790): onViewCreated - MyFragment{40530610 #0 MyFragment} 09-29 13:23:11.921: INFO/TESTING - MYFRAGMENT(4790): onActivityCreated - MyFragment{40530610 #0 MyFragment} 09-29 13:23:11.931: INFO/TESTING - MYFRAGMENT(4790): onStart - MyFragment{40530610 #0 MyFragment} 09-29 13:23:11.931: INFO/TESTING - MYFRAGMENT(4790): onResume - MyFragment{40530610 #0 MyFragment} 09-29 13:23:15.081: INFO/ActivityManager(1268): Config changed: { scale=1.0 imsi=404/45 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=2 layout=34 uiMode=17 seq=105 themeResource=null} 09-29 13:23:15.111: INFO/TESTING - MYACTIVITY(4790): onSaveInstanceState - com.example.MyActivity@405196b0 09-29 13:23:15.111: INFO/TESTING - MYFRAGMENT(4790): onPause - MyFragment{40530610 #0 MyFragment} 09-29 13:23:15.121: INFO/TESTING - MYACTIVITY(4790): onPause - com.example.MyActivity@405196b0 09-29 13:23:15.121: INFO/TESTING - MYFRAGMENT(4790): onStop - MyFragment{40530610 #0 MyFragment} 09-29 13:23:15.121: INFO/TESTING - MYACTIVITY(4790): onStop - com.example.MyActivity@405196b0 09-29 13:23:15.121: INFO/TESTING - MYACTIVITY(4790): onRetainCustomNonConfigurationInstance - com.example.MyActivity@405196b0 09-29 13:23:15.121: INFO/TESTING - MYFRAGMENT(4790): onDestroyView - MyFragment{40530610 #0 MyFragment} 09-29 13:23:15.121: INFO/TESTING - MYFRAGMENT(4790): onDestroy - MyFragment{40530610 #0 MyFragment} 09-29 13:23:15.121: INFO/TESTING - MYFRAGMENT(4790): onDetach - MyFragment{40530610 #0 MyFragment} 09-29 13:23:15.121: INFO/TESTING - MYACTIVITY(4790): onDestroy - com.example.MyActivity@405196b0 09-29 13:23:15.191: INFO/TESTING - MYACTIVITY(4790): onDetachedFromWindow - com.example.MyActivity@405196b0 09-29 13:23:15.201: INFO/TESTING - MYACTIVITY(4790): Instantiated - com.example.MyActivity@4053c438 09-29 13:23:15.201: INFO/TESTING - MYFRAGMENT(4790): Instantiated - MyFragment{4053cde0} 09-29 13:23:15.201: INFO/TESTING - MYFRAGMENT(4790): onAttach - MyFragment{4053cde0 #0 MyFragment} 09-29 13:23:15.201: INFO/TESTING - MYACTIVITY(4790): onAttachFragment - com.example.MyActivity@4053c438 09-29 13:23:15.201: INFO/TESTING - MYFRAGMENT(4790): onCreate - MyFragment{4053cde0 #0 MyFragment} 09-29 13:23:15.251: INFO/TESTING - MYACTIVITY(4790): onCreate - com.example.MyActivity@4053c438 09-29 13:23:15.251: INFO/TESTING - MYFRAGMENT(4790): onCreateView - MyFragment{4053cde0 #0 MyFragment} 09-29 13:23:15.261: INFO/TESTING - MYFRAGMENT(4790): onViewCreated - MyFragment{4053cde0 #0 MyFragment} 09-29 13:23:15.261: INFO/TESTING - MYFRAGMENT(4790): onActivityCreated - MyFragment{4053cde0 #0 MyFragment} 09-29 13:23:15.291: INFO/TESTING - MYFRAGMENT(4790): onStart - MyFragment{4053cde0 #0 MyFragment} 09-29 13:23:15.291: INFO/TESTING - MYACTIVITY(4790): onStart - com.example.MyActivity@4053c438 09-29 13:23:15.291: INFO/TESTING - MYACTIVITY(4790): onResume - com.example.MyActivity@4053c438 09-29 13:23:15.291: INFO/TESTING - MYFRAGMENT(4790): onResume - MyFragment{4053cde0 #0 MyFragment} 09-29 13:23:15.321: INFO/TESTING - MYACTIVITY(4790): onAttachedToWindow - com.example.MyActivity@4053c438

Por lo tanto, Fragment se recrea completamente nuevo, y se muestra de nuevo, todo esto mientras setRetainInstance(false)

Y ahora con setRetainInstance(true)

09-29 13:18:46.121: INFO/ActivityManager(1268): Starting: Intent { flg=0x10100000 cmp=com.example/.MyActivity } from pid 1268 09-29 13:18:46.141: INFO/TESTING - MYACTIVITY(4726): Instantiated - com.example.MyActivity@4056f2e0 09-29 13:18:46.161: INFO/TESTING - MYACTIVITY(4726): onCreate - com.example.MyActivity@4056f2e0 09-29 13:18:46.161: INFO/TESTING - MYACTIVITY(4726): onStart - com.example.MyActivity@4056f2e0 09-29 13:18:46.161: INFO/TESTING - MYACTIVITY(4726): onResume - com.example.MyActivity@4056f2e0 09-29 13:18:46.191: INFO/TESTING - MYACTIVITY(4726): onAttachedToWindow - com.example.MyActivity@4056f2e0 09-29 13:19:10.431: DEBUG/SntpClient(1268): request time failed: java.net.UnknownHostException: europe.pool.ntp.org 09-29 13:19:14.251: INFO/TESTING - MYFRAGMENT(4726): Instantiated - MyFragment{405288c0} 09-29 13:19:14.271: INFO/TESTING - MYFRAGMENT(4726): onAttach - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:14.271: INFO/TESTING - MYACTIVITY(4726): onAttachFragment - com.example.MyActivity@4056f2e0 09-29 13:19:14.271: INFO/TESTING - MYFRAGMENT(4726): onCreate - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:14.281: INFO/TESTING - MYFRAGMENT(4726): onCreateView - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:14.281: INFO/TESTING - MYFRAGMENT(4726): onViewCreated - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:14.281: INFO/TESTING - MYFRAGMENT(4726): onActivityCreated - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:14.291: INFO/TESTING - MYFRAGMENT(4726): onStart - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:14.291: INFO/TESTING - MYFRAGMENT(4726): onResume - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:21.921: INFO/ActivityManager(1268): Config changed: { scale=1.0 imsi=404/45 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=2 layout=34 uiMode=17 seq=103 themeResource=null} 09-29 13:19:21.961: INFO/TESTING - MYACTIVITY(4726): onSaveInstanceState - com.example.MyActivity@4056f2e0 09-29 13:19:21.961: INFO/TESTING - MYFRAGMENT(4726): onPause - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:21.961: INFO/TESTING - MYACTIVITY(4726): onPause - com.example.MyActivity@4056f2e0 09-29 13:19:21.961: INFO/TESTING - MYFRAGMENT(4726): onStop - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:21.961: INFO/TESTING - MYACTIVITY(4726): onStop - com.example.MyActivity@4056f2e0 09-29 13:19:21.961: INFO/TESTING - MYACTIVITY(4726): onRetainCustomNonConfigurationInstance - com.example.MyActivity@4056f2e0 09-29 13:19:21.961: INFO/TESTING - MYFRAGMENT(4726): onDestroyView - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:21.961: INFO/TESTING - MYFRAGMENT(4726): onDetach - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:21.961: INFO/TESTING - MYACTIVITY(4726): onDestroy - com.example.MyActivity@4056f2e0 09-29 13:19:22.111: INFO/TESTING - MYACTIVITY(4726): onDetachedFromWindow - com.example.MyActivity@4056f2e0 09-29 13:19:22.111: INFO/TESTING - MYACTIVITY(4726): Instantiated - com.example.MyActivity@4054a0e8 09-29 13:19:22.111: INFO/TESTING - MYFRAGMENT(4726): onAttach - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:22.111: INFO/TESTING - MYACTIVITY(4726): onAttachFragment - com.example.MyActivity@4054a0e8 09-29 13:19:22.131: INFO/TESTING - MYACTIVITY(4726): onCreate - com.example.MyActivity@4054a0e8 09-29 13:19:22.131: INFO/TESTING - MYFRAGMENT(4726): onCreateView - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:22.131: INFO/TESTING - MYFRAGMENT(4726): onViewCreated - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:22.131: INFO/TESTING - MYFRAGMENT(4726): onActivityCreated - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:22.141: INFO/TESTING - MYFRAGMENT(4726): onStart - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:22.141: INFO/TESTING - MYACTIVITY(4726): onStart - com.example.MyActivity@4054a0e8 09-29 13:19:22.141: INFO/TESTING - MYACTIVITY(4726): onResume - com.example.MyActivity@4054a0e8 09-29 13:19:22.141: INFO/TESTING - MYFRAGMENT(4726): onResume - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:22.171: INFO/TESTING - MYACTIVITY(4726): onAttachedToWindow - com.example.MyActivity@4054a0e8 09-29 13:19:22.181: INFO/TESTING - MYFRAGMENT(4726): onPause - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:22.181: INFO/TESTING - MYFRAGMENT(4726): onStop - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:22.181: INFO/TESTING - MYFRAGMENT(4726): onDestroyView - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:22.181: INFO/TESTING - MYFRAGMENT(4726): onDestroy - MyFragment{405288c0 #0 MyFragment} 09-29 13:19:22.181: INFO/TESTING - MYFRAGMENT(4726): onDetach - MyFragment{405288c0 #0 MyFragment}

Notado el efecto? La instancia de fragmento (objeto 405288c0) se retuvo, lo cual es bueno. Pero es muy probable que la instancia retenida contenga recursos, vistas y objetos que pertenecían a orientaciones anteriores, lo que podría ocasionar fugas de memoria.

Se debe tener más cuidado al escribir el código para iniciar este fragmento: siempre debe verificar la instancia preexistente.

Moraleja de la historia: setRetainInstance() se utiliza mejor para fragmentos no visuales.