savedinstancestate - Android: guardar/restaurar el estado del fragmento
restaurar copia de seguridad whatsapp (7)
Como se indica aquí: ¿Por qué usar Fragment # setRetainInstance (boolean)?
también puedes usar el método de fragmentos setRetainInstance(true)
esta manera:
public class MyFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// keep the fragment and all its data across screen rotation
setRetainInstance(true);
}
}
Tengo una actividad en la que reviso varios fragmentos. En cada fragmento tengo varias vistas ( EditText, ListView, Map
, etc.).
¿Cómo puedo guardar la instancia del fragmento que se muestra en ese momento? Necesito que funcione cuando la actividad es onPause() --> onResume()
. También necesito que funcione cuando regrese de otro fragmento (pop de backstack).
De la Activity
principal llamo al primer fragmento, luego del fragmento al que llamo el siguiente.
Código para mi actividad:
public class Activity_Main extends FragmentActivity{
public static Fragment_1 fragment_1;
public static Fragment_2 fragment_2;
public static Fragment_3 fragment_3;
public static FragmentManager fragmentManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
fragment_1 = new Fragment_1();
fragment_2 = new Fragment_2();
fragment_3 = new Fragment_3();
fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction_1 = fragmentManager.beginTransaction();
transaction_1.replace(R.id.content_frame, fragment_1);
transaction_1.commit();
}}
Entonces aquí está el código para uno de mis fragmentos:
public class Fragment_1 extends Fragment {
private EditText title;
private Button go_next;
@Override
public View onCreateView(final LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_1,
container, false);
title = (EditText) rootView.findViewById(R.id.title);
go_next = (Button) rootView.findViewById(R.id.go_next);
image.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentTransaction transaction_2 = Activity_Main.fragmentManager
.beginTransaction();
transaction_2.replace(R.id.content_frame,
Activity_Main.fragment_2);
transaction_2.addToBackStack(null);
transaction_2.commit();
});
}}
He buscado mucha información, pero nada claro. ¿Alguien puede dar una solución clara y un ejemplo, por favor?
Cuando un fragmento se mueve a la backstack, no se destruye. Todas las variables de instancia permanecen allí. Este es el lugar para guardar sus datos. En onActivityCreated
, comprueba las siguientes condiciones:
- ¿Es el paquete! = Nulo? En caso afirmativo, ahí es donde se guardan los datos (probablemente cambie la orientación).
- ¿Hay datos guardados en variables de instancia? En caso afirmativo, restaure su estado (o quizás no haga nada, porque todo es como debería ser).
- De lo contrario, tu fragmento se muestra por primera vez, crea todo de nuevo.
Editar: Aquí hay un ejemplo
public class ExampleFragment extends Fragment {
private List<String> myData;
@Override
public void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("list", (Serializable) myData);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
//probably orientation change
myData = (List<String>) savedInstanceState.getSerializable("list");
} else {
if (myData != null) {
//returning from backstack, data is fine, do nothing
} else {
//newly created, compute data
myData = computeData();
}
}
}
}
Fragmento de Android tiene algunas ventajas y algunas desventajas. La mayor desventaja del fragmento es que cuando quieres usar un fragmento lo creas. Cuando lo usa, se onCreateView
del fragmento cada vez. Si desea mantener el estado de los componentes en el fragmento, debe guardar el estado del fragmento y debe cargar su estado en el siguiente. Esto hace que la vista de fragmento sea un poco lenta y rara.
Encontré una solución y utilicé esta solución: "Todo es genial. Todos pueden intentarlo".
La primera vez que se ejecuta onCreateView
, cree la vista como una variable global. Cuando onCreateView
llamar a este fragmento en onCreateView
nuevamente, puede devolver esta vista global. El estado del componente del fragmento se mantendrá.
View view;
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
setActionBar(null);
if (view != null) {
if ((ViewGroup)view.getParent() != null)
((ViewGroup)view.getParent()).removeView(view);
return view;
}
view = inflater.inflate(R.layout.mylayout, container, false);
}
No estoy seguro de si esta pregunta todavía te molesta, ya que han pasado varios meses. Pero me gustaría compartir cómo lidié con esto. Aquí está el código fuente:
int FLAG = 0;
private View rootView;
private LinearLayout parentView;
/**
* The fragment argument representing the section number for this fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
/**
* Returns a new instance of this fragment for the given section number.
*/
public static Fragment2 newInstance(Bundle bundle) {
Fragment2 fragment = new Fragment2();
Bundle args = bundle;
fragment.setArguments(args);
return fragment;
}
public Fragment2() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
Log.e("onCreateView","onCreateView");
if(FLAG!=12321){
rootView = inflater.inflate(R.layout.fragment_create_new_album, container, false);
changeFLAG(12321);
}
parentView=new LinearLayout(getActivity());
parentView.addView(rootView);
return parentView;
}
/* (non-Javadoc)
* @see android.support.v4.app.Fragment#onDestroy()
*/
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.e("onDestroy","onDestroy");
}
/* (non-Javadoc)
* @see android.support.v4.app.Fragment#onStart()
*/
@Override
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
Log.e("onstart","onstart");
}
/* (non-Javadoc)
* @see android.support.v4.app.Fragment#onStop()
*/
@Override
public void onStop() {
// TODO Auto-generated method stub
super.onStop();
if(false){
Bundle savedInstance=getArguments();
LinearLayout viewParent;
viewParent= (LinearLayout) rootView.getParent();
viewParent.removeView(rootView);
}
parentView.removeView(rootView);
Log.e("onStop","onstop");
}
@Override
public void onPause() {
super.onPause();
Log.e("onpause","onpause");
}
@Override
public void onResume() {
super.onResume();
Log.e("onResume","onResume");
}
Y aquí está la actividad principal:
/**
* Fragment managing the behaviors, interactions and presentation of the
* navigation drawer.
*/
private NavigationDrawerFragment mNavigationDrawerFragment;
/**
* Used to store the last screen title. For use in
* {@link #restoreActionBar()}.
*/
public static boolean fragment2InstanceExists=false;
public static Fragment2 fragment2=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.activity_main);
mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager()
.findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
}
@Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
switch(position){
case 0:
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.container, Fragment1.newInstance(position+1)).commit();
break;
case 1:
Bundle bundle=new Bundle();
bundle.putInt("source_of_create",CommonMethods.CREATE_FROM_ACTIVITY);
if(!fragment2InstanceExists){
fragment2=Fragment2.newInstance(bundle);
fragment2InstanceExists=true;
}
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.container, fragment2).commit();
break;
case 2:
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.container, FolderExplorerFragment.newInstance(position+1)).commit();
break;
default:
break;
}
}
parentView
es el punto clave. Normalmente, cuando onCreateView
, simplemente utilizamos return rootView
. Pero ahora, agrego rootView a parentView
, y luego devuelvo parentView
. Para evitar "El hijo especificado ya tiene un padre. Debe llamar a removeView()
en el ..." error, necesitamos llamar a parentView.removeView(rootView)
, o el método que proporcioné es inútil. También me gustaría compartir cómo lo encontré. En primer lugar, configuré un booleano para indicar si existe la instancia. Cuando existe la instancia, la vista rootView
no se volverá a inflar. Pero entonces, logcat le dio al niño que ya tiene algo de padre, así que decidí usar otro padre como una Vista de padres intermedia. Asi es como funciona.
Espero que sea útil para ti.
Para guardar el estado de Fragment necesita implementar onSaveInstanceState()
: "También como una actividad, puede retener el estado de un fragmento usando un Bundle, en caso de que se mate el proceso de la actividad y necesite restaurar el estado del fragmento cuando el Se puede volver a crear la actividad. Puede guardar el estado durante la devolución de llamada onSaveInstanceState()
del fragmento y restaurarlo durante onCreate()
, onCreateView()
o onActivityCreated()
. Para obtener más información sobre cómo guardar el estado, consulte el documento de Actividades.
http://developer.android.com/guide/components/fragments.html#Lifecycle
Prueba esto :
@Override
protected void onPause() {
super.onPause();
if (getSupportFragmentManager().findFragmentByTag("MyFragment") != null)
getSupportFragmentManager().findFragmentByTag("MyFragment").setRetainInstance(true);
}
@Override
protected void onResume() {
super.onResume();
if (getSupportFragmentManager().findFragmentByTag("MyFragment") != null)
getSupportFragmentManager().findFragmentByTag("MyFragment").getRetainInstance();
}
Espero que esto ayude
También puede escribir esto en la etiqueta de actividad en el archivo de menifest:
android:configChanges="orientation|screenSize"
Buena suerte !!!
Puedes obtener el Fragmento actual de fragmentManager. Y si no hay ninguno en el administrador de fragmentos, puedes crear Fragment_1
public class MainActivity extends FragmentActivity {
public static Fragment_1 fragment_1;
public static Fragment_2 fragment_2;
public static Fragment_3 fragment_3;
public static FragmentManager fragmentManager;
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.main);
fragment_1 = (Fragment_1) fragmentManager.findFragmentByTag("fragment1");
fragment_2 =(Fragment_2) fragmentManager.findFragmentByTag("fragment2");
fragment_3 = (Fragment_3) fragmentManager.findFragmentByTag("fragment3");
if(fragment_1==null && fragment_2==null && fragment_3==null){
fragment_1 = new Fragment_1();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment_1, "fragment1").commit();
}
}
}
también puedes usar setRetainInstance
en true lo que hará es ignorar el método onDestroy()
en fragmento y tu aplicación irá a segundo onDestroy()
y te matará la aplicación para asignar más memoria que necesitarás para guardar todos los datos que necesitas en el paquete onSaveInstanceState
public class Fragment_1 extends Fragment {
private EditText title;
private Button go_next;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true); //Will ignore onDestroy Method (Nested Fragments no need this if parent have it)
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
onRestoreInstanceStae(savedInstanceState);
return super.onCreateView(inflater, container, savedInstanceState);
}
//Here you can restore saved data in onSaveInstanceState Bundle
private void onRestoreInstanceState(Bundle savedInstanceState){
if(savedInstanceState!=null){
String SomeText = savedInstanceState.getString("title");
}
}
//Here you Save your data
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("title", "Some Text");
}
}