2012-09-28 9 views
97

Che cosa esattamente si verifica quando si chiama setRetainInstance(true) su un Fragment? La documentazione è praticamente inesistente e questa sembra una funzione molto importante. In particolare vorrei sapere quanto di questa sequenza (che ho fatto su) è vero:Ulteriore comprensione setRetainInstance (true)

  1. l'utente ruota il dispositivo.
  2. Il frammento viene rimosso da Activity e Fragment.onDetach() viene chiamato.
  3. L'attività è distrutta; Activity.onDestroy() viene chiamato.
  4. L'oggetto java Activity viene eliminato (quando possibile dal GC).
  5. Viene creato un nuovo oggetto java Activity; il suo costruttore e onCreate() sono chiamati.
  6. Nel Activity.onCreate() abbiamo uno setContentView(...) che imposta un layout contenente un frammento oppure viene utilizzato FragmentTransaction per aggiungere un frammento.
  7. Io non sono davvero sicuro di questo, ma suppongo che Android è abbastanza intelligente per trovare il vecchio frammento, e chiamare Fragment.onAttach() per ricollegare al nuovo Activity
  8. successiva (o prima? Chi lo sa?) Activity.onResume() è chiamato.

Quindi è corretto? Android è abbastanza intelligente da trovare il vecchio frammento, anche se io uso esplicitamente FragmentTransaction.add(new MyFragment(), ...) la prima volta? E in tal caso, come evitare di aggiungere un altro frammento in onCreate()? Ho bisogno di fare qualcosa di simile ?:

risposta

86

Ok, forse ero un po 'troppo duro sulla documentazione di Android, perché ha alcune informazioni utili, ma purtroppo nessuna di esse è collegata da setRetainInstance(). Da the page about fragments

Nota: Ogni frammento richiede un identificatore univoco che il sistema può utilizzare per ripristinare il frammento se l'attività viene riavviato (e che è possibile utilizzare per catturare il frammento di eseguire le operazioni, come ad esempio remove esso). Esistono tre modi per fornire un ID per un frammento:

  • Fornire l'attributo android: id con un ID univoco.
  • Fornire l'attributo android: tag con una stringa univoca.
  • Se non si fornisce nessuno dei due precedenti, il sistema utilizza l'ID della vista Contenitore.

Questo implica fortemente che se si fa setContentView(R.layout.whatever) in Activity.onCreated() e che il layout contiene un frammento con setRetainInstance(true), poi, quando l'attività viene ricreata sarà cercata di nuovo usando il suo id o tag.

secondo luogo, per frammenti UI-less, afferma

Per aggiungere un frammento senza interfaccia utente, aggiungere il frammento dall'attività utilizzando aggiungere (frammento, String) (fornendo una stringa univoca "tag" per il frammento , anziché un ID vista). Questo aggiunge il frammento, ma, poiché non è associato a una vista nel layout dell'attività, non riceve una chiamata a onCreateView(). Quindi non è necessario implementare il metodo .

E i documenti si collegano a un ottimo esempio - FragmentRetainInstance.java che ho riprodotto qui sotto per la vostra convenienza. Fa esattamente quello che ho ipotizzato fosse la risposta nella mia domanda (if (...findFragmentByTag() == null) { ...).

Infine, ho creato la mia attività di test per vedere esattamente quali funzioni vengono chiamate. Emette questo, quando si inizia in verticale e si ruota in orizzontale. Il codice è sotto

(Questo viene modificato un po 'per rendere più facile la lettura.)

[email protected]: this() 
[email protected]: onCreate() 
[email protected]: Existing fragment not found. 
TestFragment{41583008}: this() TestFragment{41583008} 
TestFragment{41583008}: onAttach([email protected]) 
TestFragment{41583008}: onCreate() 
TestFragment{41583008}: onCreateView() 
TestFragment{41583008}: onActivityCreated() 
[email protected]: onStart() 
TestFragment{41583008}: onStart() 
[email protected]: onResume() 
TestFragment{41583008}: onResume() 

<rotate device> 

TestFragment{41583008}: onPause() 
[email protected]: onPause() 
TestFragment{41583008}: onStop() 
[email protected]: onStop() 
TestFragment{41583008}: onDestroyView() 
TestFragment{41583008}: onDetach() 
[email protected]: onDestroy() 
[email protected]: this() 
TestFragment{41583008}: onAttach([email protected]) 
[email protected]: onCreate() 
[email protected]: Existing fragment found. 
TestFragment{41583008}: onCreateView() 
TestFragment{41583008}: onActivityCreated() 
[email protected]15a3380: onStart() 
TestFragment{41583008}: onStart() 
[email protected]: onResume() 
TestFragment{41583008}: onResume() 

Nota che la documentazione Android è sbagliato: il frammento UI-less fa riceve una chiamata al onCreateView() ma è libero di restituire null.

Il codice sorgente per il codice 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()"); 
     } 
    } 

} 

sorgente per FragmentRetainInstance.java (come di 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(); 
      } 
     } 
    } 
} 
+0

Ti dispiacerebbe guardare la mia domanda e farmi sapere come implementerei la tua soluzione. La mia app funziona ma voglio rimuovere android: configChanges = "orientation | keyboardHidden | screenSize" e l'app non riuscirà a conservare il listener dei frammenti dopo la modifica della configurazione. http://stackoverflow.com/questions/35941585/avoiding-manually-handling-configuration-changes –

40

setRetainInstance() in Fragment classe è una sostituzione intelligente per onRetainCustomNonConfigurationInstance() di Activity di classe, e altro ancora.

Chiaramente indicato in the documentation.

Ecco registro di ciò che accade (Un frammento UI aggiungere su richiesta e quindi un cambiamento di configurazione):

predefinito 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 - [email protected] 
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 - [email protected] 
09-29 13:23:04.881: INFO/TESTING - MYACTIVITY(4790): onStart - [email protected] 
09-29 13:23:04.881: INFO/TESTING - MYACTIVITY(4790): onResume - [email protected] 
09-29 13:23:04.891: INFO/TESTING - MYACTIVITY(4790): onAttachedToWindow - [email protected] 
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 - [email protected] 
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 - [email protected] 
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 - [email protected] 
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 - [email protected] 
09-29 13:23:15.121: INFO/TESTING - MYACTIVITY(4790): onRetainCustomNonConfigurationInstance - [email protected] 
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 - [email protected] 
09-29 13:23:15.191: INFO/TESTING - MYACTIVITY(4790): onDetachedFromWindow - [email protected] 
09-29 13:23:15.201: INFO/TESTING - MYACTIVITY(4790): Instantiated - [email protected] 
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 - [email protected] 
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 - [email protected] 
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 - [email protected] 
09-29 13:23:15.291: INFO/TESTING - MYACTIVITY(4790): onResume - [email protected] 
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 - [email protected] 

Quindi, frammento viene ricreato completamente nuovo, e mostrato ancora una volta, tutto questo mentre setRetainInstance(false)

E ora 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 - [email protected] 
09-29 13:18:46.161: INFO/TESTING - MYACTIVITY(4726): onCreate - [email protected] 
09-29 13:18:46.161: INFO/TESTING - MYACTIVITY(4726): onStart - [email protected] 
09-29 13:18:46.161: INFO/TESTING - MYACTIVITY(4726): onResume - [email protected] 
09-29 13:18:46.191: INFO/TESTING - MYACTIVITY(4726): onAttachedToWindow - [email protected] 
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 - [email protected] 
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 - [email protected] 
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 - [email protected] 
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 - [email protected] 
09-29 13:19:21.961: INFO/TESTING - MYACTIVITY(4726): onRetainCustomNonConfigurationInstance - [email protected] 
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 - [email protected] 
09-29 13:19:22.111: INFO/TESTING - MYACTIVITY(4726): onDetachedFromWindow - [email protected] 
09-29 13:19:22.111: INFO/TESTING - MYACTIVITY(4726): Instantiated - [email protected] 
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 - [email protected] 
09-29 13:19:22.131: INFO/TESTING - MYACTIVITY(4726): onCreate - [email protected] 
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 - [email protected] 
09-29 13:19:22.141: INFO/TESTING - MYACTIVITY(4726): onResume - [email protected] 
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 - [email protected] 
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} 

Ha notato l'effetto? L'istanza di Fragment (oggetto 405288c0) è stata mantenuta, il che è buono. Ma l'istanza conservata è molto probabile che contenga risorse, viste e oggetti appartenenti a orientamenti precedenti, che potrebbero portare a perdite di memoria.

Occorre prestare particolare attenzione quando si scrive il codice per iniziare questo frammento: è necessario verificare sempre l'istanza preesistente.

Morale della storia: setRetainInstance() è la soluzione migliore per i frammenti non visivi.

+0

due tronchi mi danno la risposta .. Prima di log creare nuova istanza ogni volta (40530610,4053cde0), Dopo setRetainInstance() solo un'istanza 405288c0 –