ViewPager y fragmentos – ¿cuál es la forma correcta de almacenar el estado del fragmento?

Fragmentos parecen ser muy agradable para la separación de la lógica de la interfaz de usuario en algunos módulos. Pero junto con ViewPager su ciclo de vida sigue siendo nebuloso para mí. ¡Así que los pensamientos del Gurú son muy necesarios!

Editar

Vea la solución muda abajo 😉

Alcance

La actividad principal tiene un ViewPager con fragmentos. Esos fragmentos podrían implementar una lógica un poco diferente para otras actividades (submain), de modo que los datos de los fragmentos se rellenan a través de una interfaz de devolución de llamada dentro de la actividad. Y todo funciona bien en el primer lanzamiento, pero! …

Problema

Cuando la actividad se vuelve a crear (por ejemplo, en el cambio de orientación), también lo hacen los fragmentos de ViewPager . El código (que encontrarás a continuación) dice que cada vez que se crea la actividad intento crear un nuevo adaptador de fragmentos ViewPager igual que fragmentos (tal vez este es el problema) pero FragmentManager ya tiene todos estos fragmentos almacenados en algún lugar (¿dónde?) E inicia el mecanismo de recreación para aquellos. Así que el mecanismo de recreación llama al fragmento "antiguo" onAttach, onCreateView, etc. con mi llamada a la interfaz de devolución de llamada para iniciar los datos a través del método implementado de la Actividad. Pero este método apunta al fragmento creado recientemente que se crea mediante el método onCreate de la actividad.

Problema

Tal vez estoy usando patrones incorrectos, pero incluso Android 3 Pro libro no tiene mucho sobre él. Por lo tanto, por favor , dame un golpe de dos y señalar cómo hacerlo de la manera correcta. ¡Muchas gracias!

Código

Actividad principal

 public class DashboardActivity extends BasePagerActivity implements OnMessageListActionListener { private MessagesFragment mMessagesFragment; @Override protected void onCreate(Bundle savedInstanceState) { Logger.d("Dash onCreate"); super.onCreate(savedInstanceState); setContentView(R.layout.viewpager_container); new DefaultToolbar(this); // create fragments to use mMessagesFragment = new MessagesFragment(); mStreamsFragment = new StreamsFragment(); // set titles and fragments for view pager Map<String, Fragment> screens = new LinkedHashMap<String, Fragment>(); screens.put(getApplicationContext().getString(R.string.dashboard_title_dumb), new DumbFragment()); screens.put(getApplicationContext().getString(R.string.dashboard_title_messages), mMessagesFragment); // instantiate view pager via adapter mPager = (ViewPager) findViewById(R.id.viewpager_pager); mPagerAdapter = new BasePagerAdapter(screens, getSupportFragmentManager()); mPager.setAdapter(mPagerAdapter); // set title indicator TitlePageIndicator indicator = (TitlePageIndicator) findViewById(R.id.viewpager_titles); indicator.setViewPager(mPager, 1); } /* set of fragments callback interface implementations */ @Override public void onMessageInitialisation() { Logger.d("Dash onMessageInitialisation"); if (mMessagesFragment != null) mMessagesFragment.loadLastMessages(); } @Override public void onMessageSelected(Message selectedMessage) { Intent intent = new Intent(this, StreamActivity.class); intent.putExtra(Message.class.getName(), selectedMessage); startActivity(intent); } 

BasePagerActivity también conocido como ayudante

 public class BasePagerActivity extends FragmentActivity { BasePagerAdapter mPagerAdapter; ViewPager mPager; } 

Adaptador

 public class BasePagerAdapter extends FragmentPagerAdapter implements TitleProvider { private Map<String, Fragment> mScreens; public BasePagerAdapter(Map<String, Fragment> screenMap, FragmentManager fm) { super(fm); this.mScreens = screenMap; } @Override public Fragment getItem(int position) { return mScreens.values().toArray(new Fragment[mScreens.size()])[position]; } @Override public int getCount() { return mScreens.size(); } @Override public String getTitle(int position) { return mScreens.keySet().toArray(new String[mScreens.size()])[position]; } // hack. we don't want to destroy our fragments and re-initiate them after @Override public void destroyItem(View container, int position, Object object) { // TODO Auto-generated method stub } } 

Fragmento

 public class MessagesFragment extends ListFragment { private boolean mIsLastMessages; private List<Message> mMessagesList; private MessageArrayAdapter mAdapter; private LoadMessagesTask mLoadMessagesTask; private OnMessageListActionListener mListener; // define callback interface public interface OnMessageListActionListener { public void onMessageInitialisation(); public void onMessageSelected(Message selectedMessage); } @Override public void onAttach(Activity activity) { super.onAttach(activity); // setting callback mListener = (OnMessageListActionListener) activity; mIsLastMessages = activity instanceof DashboardActivity; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { inflater.inflate(R.layout.fragment_listview, container); mProgressView = inflater.inflate(R.layout.listrow_progress, null); mEmptyView = inflater.inflate(R.layout.fragment_nodata, null); return super.onCreateView(inflater, container, savedInstanceState); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // instantiate loading task mLoadMessagesTask = new LoadMessagesTask(); // instantiate list of messages mMessagesList = new ArrayList<Message>(); mAdapter = new MessageArrayAdapter(getActivity(), mMessagesList); setListAdapter(mAdapter); } @Override public void onResume() { mListener.onMessageInitialisation(); super.onResume(); } public void onListItemClick(ListView l, View v, int position, long id) { Message selectedMessage = (Message) getListAdapter().getItem(position); mListener.onMessageSelected(selectedMessage); super.onListItemClick(l, v, position, id); } /* public methods to load messages from host acitivity, etc... */ } 

Solución

La solución estúpida es guardar los fragmentos dentro de onSaveInstanceState (de la actividad del host) con putFragment y obtenerlos dentro de onCreate vía getFragment. Pero todavía tengo un extraño sentimiento de que las cosas no deberían funcionar así … Vea el código abajo:

  @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); getSupportFragmentManager() .putFragment(outState, MessagesFragment.class.getName(), mMessagesFragment); } protected void onCreate(Bundle savedInstanceState) { Logger.d("Dash onCreate"); super.onCreate(savedInstanceState); ... // create fragments to use if (savedInstanceState != null) { mMessagesFragment = (MessagesFragment) getSupportFragmentManager().getFragment( savedInstanceState, MessagesFragment.class.getName()); StreamsFragment.class.getName()); } if (mMessagesFragment == null) mMessagesFragment = new MessagesFragment(); ... } 

Cuando el FragmentPagerAdapter agrega un fragmento al FragmentManager, utiliza una etiqueta especial basada en la posición particular en la que se colocará el fragmento. FragmentPagerAdapter.getItem(int position) sólo se llama cuando no existe un fragmento para esa posición. Después de girar, Android notará que ya creó / guardó un fragmento para esta posición en particular y por lo que simplemente intenta volver a conectar con él con FragmentManager.findFragmentByTag() , en lugar de crear uno nuevo. Todo esto viene gratis cuando se utiliza el FragmentPagerAdapter y es por eso que es habitual tener su código de inicialización de fragmentos dentro del getItem(int) .

Incluso si no usamos un FragmentPagerAdapter , no es una buena idea crear un nuevo fragmento cada vez en Activity.onCreate(Bundle) . Como habrás notado, cuando se agregue un fragmento al FragmentManager, se volverá a crear para ti después de girar y no hay necesidad de añadirlo de nuevo. Hacerlo es una causa común de errores al trabajar con fragmentos.

Un enfoque habitual cuando se trabaja con fragmentos es el siguiente:

 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... CustomFragment fragment; if (savedInstanceState != null) { fragment = (CustomFragment) getSupportFragmentManager().findFragmentByTag("customtag"); } else { fragment = new CustomFragment(); getSupportFragmentManager().beginTransaction().add(R.id.container, fragment, "customtag").commit(); } ... } 

Cuando se utiliza un FragmentPagerAdapter , renunciamos a la administración de fragmentos al adaptador y no tenemos que realizar los pasos anteriores. De forma predeterminada, sólo precargará un fragmento delante y detrás de la posición actual (aunque no los destruye a menos que esté utilizando FragmentStatePagerAdapter ). Esto es controlado por ViewPager.setOffscreenPageLimit (int) . Debido a esto, no se garantiza que los métodos de llamada directa sobre los fragmentos fuera del adaptador sean válidos, ya que pueden no estar vivos.

Para cortar un cuento corto, su solución para usar putFragment para poder obtener una referencia después no es tan loco, y no tan diferente a la forma normal de usar fragmentos de todos modos (arriba). Es difícil obtener una referencia de otra manera porque el fragmento es agregado por el adaptador, y no usted personalmente. Sólo asegúrese de que la offscreenPageLimit es lo suficientemente alta para cargar los fragmentos deseados en todo momento, ya que confía en que esté presente. Esto evita las capacidades de carga perezosa de ViewPager, pero parece ser lo que usted desea para su aplicación.

Otro enfoque consiste en anular FragmentPageAdapter.instantiateItem(View, int) y guardar una referencia al fragmento devuelto de la súper llamada antes de devolverlo (tiene la lógica para encontrar el fragmento, si ya está presente).

Para obtener una imagen más completa, eche un vistazo a algunas de las fuentes de FragmentPagerAdapter (short) y ViewPager (long).

Quiero ofrecer una solución que se expande en la maravillosa respuesta de antonyt y la mención de reemplazar FragmentPageAdapter.instantiateItem(View, int) para guardar las referencias a Fragments creados para que puedas trabajar en ellos más tarde. Esto también debería funcionar con FragmentStatePagerAdapter ; Vea las notas para más detalles.


Este es un ejemplo sencillo de cómo obtener una referencia a los Fragments devueltos por FragmentPagerAdapter que no se basan en las tags internas establecidas en los Fragments . La clave es anular instantiateItem() y guardar las referencias allí en vez de en getItem() .

 public class SomeActivity extends Activity { private FragmentA m1stFragment; private FragmentB m2ndFragment; // other code in your Activity... private class CustomPagerAdapter extends FragmentPagerAdapter { // other code in your custom FragmentPagerAdapter... public CustomPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { // Do NOT try to save references to the Fragments in getItem(), // because getItem() is not always called. If the Fragment // was already created then it will be retrieved from the FragmentManger // and not here (ie getItem() won't be called again). switch (position) { case 0: return new FragmentA(); case 1: return new FragmentB(); default: // This should never happen. Always account for each position above return null; } } // Here we can finally safely save a reference to the created // Fragment, no matter where it came from (either getItem() or // FragmentManger). Simply save the returned Fragment from // super.instantiateItem() into an appropriate reference depending // on the ViewPager position. @Override public Object instantiateItem(ViewGroup container, int position) { Fragment createdFragment = (Fragment) super.instantiateItem(container, position); // save the appropriate reference depending on position switch (position) { case 0: m1stFragment = (FragmentA) createdFragment; break; case 1: m2ndFragment = (FragmentB) createdFragment; break; } return createdFragment; } } public void someMethod() { // do work on the referenced Fragments, but first check if they // even exist yet, otherwise you'll get an NPE. if (m1stFragment != null) { // m1stFragment.doWork(); } if (m2ndFragment != null) { // m2ndFragment.doSomeWorkToo(); } } } 

O si prefiere trabajar con tags lugar de las variables de miembro de clase / referencias a los Fragments también puede tomar las tags establecidas por FragmentPagerAdapter de la misma manera: NOTA: esto no se aplica a FragmentStatePagerAdapter ya que no establece tags al crear Sus Fragments .

 @Override public Object instantiateItem(ViewGroup container, int position) { Fragment createdFragment = (Fragment) super.instantiateItem(container, position); // get the tags set by FragmentPagerAdapter switch (position) { case 0: String firstTag = createdFragment.getTag(); break; case 1: String secondTag = createdFragment.getTag(); break; } // ... save the tags somewhere so you can reference them later return createdFragment; } 

Tenga en cuenta que este método no se basan en imitar la tag interna establecida por FragmentPagerAdapter y en su lugar utiliza las API adecuadas para recuperarlas. De esta manera, incluso si la tag cambia en futuras versiones de SupportLibrary , seguirá siendo segura.


No olvides que dependiendo del diseño de tu Activity , los Fragments que estás intentando trabajar pueden o no existir aún, así que debes tener en cuenta esto haciendo chequeos null antes de usar tus referencias.

Además, si en vez de eso trabajas con FragmentStatePagerAdapter , entonces no querrás guardar referencias duras a tus Fragments ya que podrías tener muchas de ellas y las referencias duras las mantendrían innecesariamente en la memoria. En su lugar, guarde las referencias de Fragment en WeakReference variables WeakReference en lugar de las estándar. Me gusta esto:

 WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment); // ...and access them like so Fragment firstFragment = m1stFragment.get(); if (firstFragment != null) { // reference hasn't been cleared yet; do work... } 

Encontré otra solución relativamente fácil para su pregunta.

Como se puede ver en el código fuente FragmentPagerAdapter , los fragmentos gestionados por FragmentPagerAdapter almacenan en FragmentManager bajo la etiqueta generada mediante:

 String tag="android:switcher:" + viewId + ":" + index; 

viewId es container.getId() , el container es su instancia de ViewPager . El index es la posición del fragmento. Por lo tanto, puede guardar el identificador de objeto en outState :

 @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("viewpagerid" , mViewPager.getId() ); } @Override protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main); if (savedInstanceState != null) viewpagerid=savedInstanceState.getInt("viewpagerid", -1 ); MyFragmentPagerAdapter titleAdapter = new MyFragmentPagerAdapter (getSupportFragmentManager() , this); mViewPager = (ViewPager) findViewById(R.id.pager); if (viewpagerid != -1 ){ mViewPager.setId(viewpagerid); }else{ viewpagerid=mViewPager.getId(); } mViewPager.setAdapter(titleAdapter); 

Si desea comunicarse con este fragmento, puede obtener si de FragmentManager , como:

 getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewpagerid + ":0") 

Quiero ofrecer una solución alternativa para tal vez un caso ligeramente diferente, ya que muchas de mis búsquedas de respuestas me llevaron a este hilo.

Mi caso – Estoy creando / añadiendo páginas de forma dinámica y deslizando en un ViewPager, pero cuando se gira (onConfigurationChange) termino con una nueva página, porque por supuesto OnCreate se llama de nuevo. Pero quiero mantener referencia a todas las páginas que se crearon antes de la rotación.

Problema – No tengo identificadores únicos para cada fragmento que creo, por lo que la única forma de referencia era almacenar de alguna manera referencias en un Array para restaurar después del cambio de rotación / configuración.

Solución : el concepto clave era tener la Actividad (que muestra los Fragmentos) también administrar la matriz de referencias a Fragmentos existentes, ya que esta actividad puede utilizar los Paquetes en onSaveInstanceState

 public class MainActivity extends FragmentActivity 

Así que dentro de esta Actividad, declaro un miembro privado para rastrear las páginas abiertas

 private List<Fragment> retainedPages = new ArrayList<Fragment>(); 

Esto se actualiza cada vez que onSaveInstanceState es llamado y restaurado en onCreate

 @Override protected void onSaveInstanceState(Bundle outState) { retainedPages = _adapter.exportList(); outState.putSerializable("retainedPages", (Serializable) retainedPages); super.onSaveInstanceState(outState); } 

… una vez almacenada, puede recuperarse …

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState != null) { retainedPages = (List<Fragment>) savedInstanceState.getSerializable("retainedPages"); } _mViewPager = (CustomViewPager) findViewById(R.id.viewPager); _adapter = new ViewPagerAdapter(getApplicationContext(), getSupportFragmentManager()); if (retainedPages.size() > 0) { _adapter.importList(retainedPages); } _mViewPager.setAdapter(_adapter); _mViewPager.setCurrentItem(_adapter.getCount()-1); } 

Éstos eran los cambios necesarios a la actividad principal, y así que necesitaba los miembros y los métodos dentro de mi FragmentPagerAdapter para que esto funcione, así que dentro

 public class ViewPagerAdapter extends FragmentPagerAdapter 

Una construcción idéntica (como se muestra arriba en MainActivity)

 private List<Fragment> _pages = new ArrayList<Fragment>(); 

Y esta sincronización (como se utiliza anteriormente en onSaveInstanceState) es apoyado específicamente por los métodos

 public List<Fragment> exportList() { return _pages; } public void importList(List<Fragment> savedPages) { _pages = savedPages; } 

Y finalmente, en la clase de fragmentos

 public class CustomFragment extends Fragment 

Para que todo esto funcionara, hubo dos cambios, primero

 public class CustomFragment extends Fragment implements Serializable 

Y luego agregar esto a onCreate para que los fragmentos no se destruyan

 setRetainInstance(true); 

Todavía estoy en el proceso de envolver mi cabeza alrededor de Fragmentos y Android ciclo de vida, por lo que la advertencia aquí es que puede haber redundancias / ineficiencias en este método. Pero funciona para mí y espero que pueda ser útil para otros con casos similares a los míos.

Mi solución es muy grosera pero funciona: siendo mis fragmentos creados dinámicamente a partir de datos retenidos, simplemente PageAdapter todos los fragmentos del PageAdapter antes de llamar a super.onSaveInstanceState() y luego los recreo en la creación de actividad:

 @Override protected void onSaveInstanceState(Bundle outState) { outState.putInt("viewpagerpos", mViewPager.getCurrentItem() ); mSectionsPagerAdapter.removeAllfragments(); super.onSaveInstanceState(outState); } 

No se pueden eliminar en onDestroy() , de lo contrario se obtiene esta excepción:

java.lang.IllegalStateException: No se puede realizar esta acción después de onSaveInstanceState

Aquí el código en el adaptador de página:

 public void removeAllfragments() { if ( mFragmentList != null ) { for ( Fragment fragment : mFragmentList ) { mFm.beginTransaction().remove(fragment).commit(); } mFragmentList.clear(); notifyDataSetChanged(); } } 

Sólo onCreate() la página actual y la restauro en onCreate() , después de que se hayan creado los fragmentos.

 if (savedInstanceState != null) mViewPager.setCurrentItem( savedInstanceState.getInt("viewpagerpos", 0 ) ); 

¿Qué es ese BasePagerAdapter ? Debe utilizar uno de los adaptadores de buscapersonas estándar, ya sea FragmentPagerAdapter o FragmentStatePagerAdapter , dependiendo de si desea que Fragmentos que ya no sean necesarios por ViewPager para mantenerse alrededor (el primero) o tener su estado guardado (el último) y re -creado si es necesario de nuevo.

El código de ejemplo para usar ViewPager se puede encontrar aquí

Es cierto que el manejo de fragmentos en un paginador de vista a través de instancias de actividad es un poco complicado, ya que el FragmentManager en el marco se encarga de salvar el estado y restaurar cualquier fragmento activo que el buscapersonas haya realizado. Todo esto realmente significa que el adaptador al inicializar necesita asegurarse de que vuelve a conectarse con los fragmentos restaurados que hay. Puedes ver el código para FragmentPagerAdapter o FragmentStatePagerAdapter para ver cómo se hace esto.

Si alguien está teniendo problemas con su FragmentStatePagerAdapter no correctamente la restauración del estado de sus fragmentos … es decir … nuevos Fragmentos están siendo creados por el FragmentStatePagerAdapter en lugar de restaurarlos de estado …

Asegúrese de llamar a ViewPager.setOffscreenPageLimit() ANTES de llamar a ViewPager.setAdapeter(fragmentStatePagerAdapter)

Al llamar a ViewPager.setOffscreenPageLimit() … el ViewPager buscará inmediatamente su adaptador e intentará obtener sus fragmentos. Esto podría ocurrir antes de que ViewPager tenga la oportunidad de restaurar los Fragmentos de savedInstanceState (creando así nuevos Fragmentos que no se pueden reinicializar desde SavedInstanceState porque son nuevos).

Para obtener los fragmentos después de cambiar la orientación que tiene que utilizar el .getTag ().

  getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewPagerId + ":" + positionOfItemInViewPager) 

Para un poco más de manejo escribí mi propia ArrayList para mi PageAdapter para obtener el fragmento por viewPagerId y el FragmentClass en cualquier posición:

 public class MyPageAdapter extends FragmentPagerAdapter implements Serializable { private final String logTAG = MyPageAdapter.class.getName() + "."; private ArrayList<MyPageBuilder> fragmentPages; public MyPageAdapter(FragmentManager fm, ArrayList<MyPageBuilder> fragments) { super(fm); fragmentPages = fragments; } @Override public Fragment getItem(int position) { return this.fragmentPages.get(position).getFragment(); } @Override public CharSequence getPageTitle(int position) { return this.fragmentPages.get(position).getPageTitle(); } @Override public int getCount() { return this.fragmentPages.size(); } public int getItemPosition(Object object) { //benötigt, damit bei notifyDataSetChanged alle Fragemnts refrehsed werden Log.d(logTAG, object.getClass().getName()); return POSITION_NONE; } public Fragment getFragment(int position) { return getItem(position); } public String getTag(int position, int viewPagerId) { //getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.shares_detail_activity_viewpager + ":" + myViewPager.getCurrentItem()) return "android:switcher:" + viewPagerId + ":" + position; } public MyPageBuilder getPageBuilder(String pageTitle, int icon, int selectedIcon, Fragment frag) { return new MyPageBuilder(pageTitle, icon, selectedIcon, frag); } public static class MyPageBuilder { private Fragment fragment; public Fragment getFragment() { return fragment; } public void setFragment(Fragment fragment) { this.fragment = fragment; } private String pageTitle; public String getPageTitle() { return pageTitle; } public void setPageTitle(String pageTitle) { this.pageTitle = pageTitle; } private int icon; public int getIconUnselected() { return icon; } public void setIconUnselected(int iconUnselected) { this.icon = iconUnselected; } private int iconSelected; public int getIconSelected() { return iconSelected; } public void setIconSelected(int iconSelected) { this.iconSelected = iconSelected; } public MyPageBuilder(String pageTitle, int icon, int selectedIcon, Fragment frag) { this.pageTitle = pageTitle; this.icon = icon; this.iconSelected = selectedIcon; this.fragment = frag; } } public static class MyPageArrayList extends ArrayList<MyPageBuilder> { private final String logTAG = MyPageArrayList.class.getName() + "."; public MyPageBuilder get(Class cls) { // Fragment über FragmentClass holen for (MyPageBuilder item : this) { if (item.fragment.getClass().getName().equalsIgnoreCase(cls.getName())) { return super.get(indexOf(item)); } } return null; } public String getTag(int viewPagerId, Class cls) { // Tag des Fragment unabhängig vom State zB nach bei Orientation change for (MyPageBuilder item : this) { if (item.fragment.getClass().getName().equalsIgnoreCase(cls.getName())) { return "android:switcher:" + viewPagerId + ":" + indexOf(item); } } return null; } } 

Así que sólo crea un MyPageArrayList con los fragmentos:

  myFragPages = new MyPageAdapter.MyPageArrayList(); myFragPages.add(new MyPageAdapter.MyPageBuilder( getString(R.string.widget_config_data_frag), R.drawable.ic_sd_storage_24dp, R.drawable.ic_sd_storage_selected_24dp, new WidgetDataFrag())); myFragPages.add(new MyPageAdapter.MyPageBuilder( getString(R.string.widget_config_color_frag), R.drawable.ic_color_24dp, R.drawable.ic_color_selected_24dp, new WidgetColorFrag())); myFragPages.add(new MyPageAdapter.MyPageBuilder( getString(R.string.widget_config_textsize_frag), R.drawable.ic_settings_widget_24dp, R.drawable.ic_settings_selected_24dp, new WidgetTextSizeFrag())); 

Y agregarlos a la viewPager:

  mAdapter = new MyPageAdapter(getSupportFragmentManager(), myFragPages); myViewPager.setAdapter(mAdapter); 

Después de esto usted puede conseguir después de la orientación cambiar el fragmento correcto usando su clase:

  WidgetDataFrag dataFragment = (WidgetDataFrag) getSupportFragmentManager() .findFragmentByTag(myFragPages.getTag(myViewPager.getId(), WidgetDataFrag.class)); 

Me surgió con esta solución simple y elegante. Asume que la actividad es responsable de crear los Fragmentos, y el Adaptador sólo les sirve.

Este es el código del adaptador (nada extraño aquí, excepto por el hecho de que mFragments es una lista de fragmentos mantenidos por la Actividad)

 class MyFragmentPagerAdapter extends FragmentStatePagerAdapter { public MyFragmentPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return mFragments.get(position); } @Override public int getCount() { return mFragments.size(); } @Override public int getItemPosition(Object object) { return POSITION_NONE; } @Override public CharSequence getPageTitle(int position) { TabFragment fragment = (TabFragment)mFragments.get(position); return fragment.getTitle(); } } 

Todo el problema de este hilo es obtener una referencia de los "viejos" fragmentos, así que utilizo este código en la actividad de onCreate.

  if (savedInstanceState!=null) { if (getSupportFragmentManager().getFragments()!=null) { for (Fragment fragment : getSupportFragmentManager().getFragments()) { mFragments.add(fragment); } } } 

Por supuesto, puede afinar este código si es necesario, por ejemplo, asegurándose de que los fragmentos son instancias de una clase en particular.

añadir:

  @SuppressLint("ValidFragment") 

Antes de tu clase

No funciona hacer algo como esto:

 @SuppressLint({ "ValidFragment", "HandlerLeak" }) 
  • Proyecto de la Biblioteca de Android - Definición de clases
  • ¿Cómo abrir NavigationDrawer sólo al inicio de la primera aplicación?
  • ¿Hay algún patrón en el método Random ()?
  • ContentProvider con varias tablas
  • Parcelable y herencia en Android
  • Editar entrada de texto con patrón android
  • ¿Hay un patrón de diseño para reducir la duplicación de código cuando subclases Actividades en Android?
  • Forma correcta de dar formato a la fecha con cadenas como hoy, ayer, mañana, etc
  • Android.util.Log al publicar - ¿qué puedo hacer / no hacer
  • MVP para Android: uso seguro Contexto en Presenter
  • Ejemplo de la necesidad del cliente del DESECHO de Androide que implementa el patrón de la ejecución de REST de Virgil Dobjanschi
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.