2011-08-02 27 views
9

Estoy diseñando una aplicación que permite a los usuarios pasar de una página a otra en una ViewPager. He estado luchando por descubrir cómo es posible eliminar una instancia de Fragment de una página cuando ya no está visible en la pantalla, almacenarla en caché (por ejemplo, un HashMap) y restaurarla para que cuando el usuario vuelve a esa página, las vistas y todo lo demás estará en el mismo estado que antes de la eliminación. Por ejemplo, mi primera página es una pantalla de inicio de sesión que hace que ciertos elementos de diseño en esa página en particular sean visibles/invisibles en un inicio de sesión exitoso. Cuando paso hacia adelante suficientes páginas y vuelvo a la primera página, el diseño se restablece. Esto se convierte en un problema para otra de mis páginas que contiene una gran cuadrícula de datos de desplazamiento horizontal/vertical que utilizo un hilo en el fondo para dibujar cuando se inicializa. Utilizo un diálogo de progreso para notificar al usuario sobre el progreso de la carga y eso se vuelve realmente molesto cada vez que tengo que cargarlo.Android: Viewpager y FragmentStatePageAdapter

por lo que hice algunas investigaciones ...

he echado un vistazo a través del código fuente para FragmentStatePageAdapter y en la devolución de llamada destroyItem(), el estado de la instancia Fragmento de ser eliminado se guarda en un ArrayList. Cuando se crea una nueva instancia del Fragmento en la devolución de llamada instantiateItem(), si todavía no existe una instancia de un elemento (realizan un seguimiento de esto utilizando una ArrayList), se crea una nueva instancia de Fragment y se guarda su estado se inicializa con los datos Fragment.SavedState correspondientes. Desafortunadamente, estos datos no incluyen el estado en el que se encontraban las Vistas aunque noté que para las páginas con GridView/ListView, el estado de las Vistas se restauraba de alguna manera (si me desplazaba a una posición aleatoria, volteaba algunas páginas y regresaba , no se restablecería).

Según la API:

El estado guardado no puede contener dependencias de otros fragmentos - que es que no puede utilizar putFragment (Bundle, String, fragmento) para almacenar una referencia fragmento porque esa referencia puede no ser válida cuando este estado guardado se usa posteriormente. Del mismo modo, el objetivo y el resultado del Fragmento no se incluyen en este estado.

Al ser un novato en Android, no estoy muy seguro de entender la última declaración.

Dicho esto, ¿hay alguna manera de almacenar en caché el estado de la vista? Si no, creo que seguiré adelante y dejaré todas las páginas de fragmentos en la memoria.

Respuesta

1

Mirando las diversas piezas de documentación, mi mejor estimación es que las vistas que está creando no tienen una ID adjunta. Suponiendo que el estado guardado del fragmento se crea desde Fragment.onSaveInstanceState, el fragmento guardará automáticamente el estado de cualquier vista que tenga un id. Probablemente tengas una identificación predeterminada asociada a tu ListView/GridView si las creaste desde un archivo de diseño. También puede asociar una identificación con las vistas llamando a setId.

Además, para su fragmento personalizado, también puede tener que hacer algo personalizado en onSaveInstanceState.

4

que tenían el mismo problema problema y lo resolvió mediante la implementación de estas dos funciones

public void onSaveInstanceState (Bundle outState) 
    public void onActivityCreated (Bundle savedInstanceState) 

en los fragmentos que quería salvar. En la primera función, debe guardar en el paquete la fecha en que necesita restaurar las vistas (en mi caso, tenía un montón de spinner, así que usé una matriz int para guardar sus posiciones).La segunda función, que se llama al restaurar su fragmento, es donde implementa el proceso de restauración.

Espero que esto ayude. También hice que mi adaptador heredara de FragmentStatePageAdapter, pero no estoy seguro de que esto sea obligatorio.

+3

Es necesario heredar de FragmentStatePagerAdapter, si sólo utiliza FragmentPagerAdapter continuación onSaveInstanceState no se llamará. – Scott

2

Listado de main.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" android:layout_width="fill_parent" 
    android:layout_height="fill_parent"> 
    <TextView android:text="Page 1" android:id="@+id/textViewHeader" 
     android:layout_width="fill_parent" android:layout_height="wrap_content" 
     android:gravity="center" android:padding="10dip" android:textStyle="bold"></TextView> 
    <android.support.v4.view.ViewPager 
     android:layout_width="fill_parent" android:layout_height="fill_parent" 
     android:id="@+id/viewPager" /> 
</LinearLayout> 

Configuración del ViewPager

ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager); 
MyPagerAdapter adapter = new MyPagerAdapter(this); 
viewPager.setAdapter(adapter); 

El PagerAdapter

@Override 
public void destroyItem(View view, int arg1, Object object) { 
     ((ViewPager) view).removeView((View)object); 
} 
@Override 
public int getCount() { 
      return views.size(); 
} 
@Override 
public Object instantiateItem(View view, int position) { 
      View view = views.get(position); 
      ((ViewPager) view).addView(view); 
      return view; 
} 
@Override 
public boolean isViewFromObject(View view, Object object) { 
      return view == object; 
} 

vistazo aquí para más detalles view pager example

1

H Este es un ejemplo de cómo implementé el almacenamiento en caché en PagerAdapter. Después de llenar el caché, todas las solicitudes de vistas futuras se sirven desde el caché, solo se reemplazan los datos.

public class TestPageAdapter extends PagerAdapter{ 

private int MAX_SIZE = 3; 
private ArrayList<SoftReference<View>> pageCache = new ArrayList<SoftReference<View>>(3); 


public TestPageAdapter(Context context){ 
    // do some initialization 
} 

@Override 
public int getCount() { 
    // number of pages 
} 

private void addToCache(View view){ 
    if (pageCache.size() < MAX_SIZE){ 
     pageCache.add(new SoftReference<View>(view)); 
    } else { 
     for(int n = (pageCache.size()-1); n >= 0; n--) { 
      SoftReference<View> cachedView = pageCache.get(n); 
      if (cachedView.get() == null){ 
       pageCache.set(n, new SoftReference<View>(view)); 
       return; 
      } 
     } 
    } 
} 

private View fetchFromCache(){ 
    for(int n = (pageCache.size()-1); n>= 0; n--) { 
     SoftReference<View> reference = pageCache.remove(n); 
     View view = reference.get(); 
     if (view != null) { 
      return view; 
     } 
    } 
    return null; 
} 

@Override 
public Object instantiateItem(View collection, int position) { 
    View view = fetchFromCache(); 
    if (view == null) { 
     // not in cache, inflate manually 
     LayoutInflater inflater = (LayoutInflater) collection.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     view = inflater.inflate(R.layout.page, null); 
    } 
    setData(view, position); 
    ((ViewPager) collection).addView(view, 0); 
    return view;   
} 

private void setData(View view, int position){ 
    // set page data (images, text ....) 
} 

public void setPrimaryItem(ViewGroup container, int position, Object object) { 
    currentItem = (View)object; 
} 

public View getCurrentItem() { 
    return currentItem; 
} 

@Override 
public boolean isViewFromObject(View view, Object object) { 
    return view == ((View) object); 
} 

@Override 
public void destroyItem(View collection, int arg1, Object view) { 
    ((ViewPager) collection).removeView((View) view); 
    addToCache((View) view); 
} 

} 
0

también me encontré con este problema cuando yo estaba usando PagerSlidingTabStrip y el uso y la instancia de FragmentPagerAdapter, el cambio a FragmentStatePagerAdapter definitivamente trabajado.

Luego uso onSaveInstanceState() para guardar Estado

Cuestiones relacionadas