Comprensión adicional setRetainInstance (true)

¿Qué sucede exactamente cuando llamas setRetainInstance(true) en un Fragment ? La documentación es prácticamente inexistente y esto parece una función muy importante. En concreto, quiero saber cuánto de esta secuencia (que he inventado) es cierto:

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

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

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

¿Por qué no hay nada de esto en la documentación? Ha no, sólo bromeo no responder a eso!

Ok, tal vez yo era un poco demasiado dura en la documentación de Android, porque tiene alguna información útil, pero lamentablemente ninguno de ellos está vinculado a setRetainInstance() . De la página sobre fragments

Nota: cada fragmento requiere un identificador único que el sistema puede utilizar para restaurar el fragmento si se reinicia la actividad (y que puede utilizar para capturar el fragmento para realizar transacciones, como quitarlo). Hay tres maneras de proporcionar un ID para un fragmento:

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

Esto implica fuertemente que si usted hace setContentView(R.layout.whatever) en Activity.onCreated() y ese diseño contiene un fragmento con setRetainInstance(true) , entonces cuando la actividad es recreada se buscará de nuevo usando su id o etiqueta .

En segundo lugar, para los fragmentos sin IU,

Para agregar un fragmento sin una interfaz de usuario, agregue el fragmento de la actividad mediante add (Fragment, String) (que proporciona una cadena única "tag" para el fragmento, en lugar de una ID de vista). Esto agrega el fragmento, pero, debido a que no está asociado con una vista en el diseño de la actividad, no recibe una llamada a onCreateView (). Por lo tanto, no es necesario implementar ese método.

Y los documentos enlazan 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. Produce esto, cuando empiezas en vertical y gira 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 (como de la 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 sustituto inteligente para onRetainCustomNonConfigurationInstance() de la clase Activity y mucho más.

Indicado claramente en la documentación .

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

Predeterminado 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, Fragmento se recrea totalmente 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} 

¿Notó el efecto? Se conservó la instancia de fragmento (objeto 405288c0) que es buena. Pero la instancia retenida es muy probable que contenga recursos y vistas y objetos que pertenecieron a orientaciones anteriores, lo que podría conducir a fugas de memoria.

Se debe tener cuidado al escribir el código para iniciar este fragmento: siempre debe comprobar si existe una instancia preexistente.

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

Asumir una aplicación con MainActivity y un fragmento llamado Fragmento con RecyclerView.

Miremos más de cerca. Retain Fragment aprovecha el hecho de que la vista de un fragmento puede ser destruida y recreada sin tener que destruir el fragmento mismo.

Durante los cambios de configuración, el FragmentManager primero destruye las vistas del fragmento en su lista. Las vistas de fragmentos siempre se destruyen y se vuelven a crear en un cambio de configuración, por si acaso se dispone de mejores recursos de coincidencia.

Sobre la rotación dentro de la actividad

La vista del fragmento se destruye pero el fragmento en sí no lo es. Cuando se crea la nueva Actividad, el nuevo FragmentManager encuentra el fragmento retenido y vuelve a crear su vista.

Un fragmento retenido no se destruye, pero se separa de la actividad moribunda . Esto pone el fragmento en un estado retenido. El Fragmento todavía existe, pero no está alojado en ninguna actividad.

Ciclo de vida detallado del fragmento

Como se explica arriba aquí https://stackoverflow.com/a/12641575/7336940

En rotación: onCreate no se llamará cuando setRetainInstance (true), ya que Fragment no se destruye. OnCreateView se llamará para crear la vista de nuevo.

  • Android: orientación de la vista previa de la cámara en modo vertical
  • Cómo aumentar la velocidad de rotación en android?
  • Box2D rotar un objeto, ¿cómo?
  • Android: gira el lienzo alrededor del centro de la pantalla
  • Android gire TextView en nivel de API> = 8
  • Rotar la vista de anuncio con API 8
  • Cómo evitar que toda la pantalla de actividad de rotación en android
  • Rotar correctamente las imágenes web utilizando Picasso de Square
  • Metadatos de rotación de vídeo Mp4
  • Perder datos al girar la pantalla
  • Cómo utilizar el evento del sensor Android para determinar si el dispositivo está orientado hacia arriba o hacia abajo
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.