with viewpager studio practice fragments example best android android-fragments android-viewpager

viewpager - slide android studio



La vista del Fragmento de ViewPager se pierde cuando el Fragmento principal de ViewPager se oculta y luego se muestra (5)

No estás proporcionando suficiente información para tu problema específico, así que construí un proyecto de muestra que intenta reproducir tu problema: la aplicación tiene una actividad que contiene un fragmento ( PagerFragment ) dentro de un diseño relativo y debajo de este diseño tengo un botón que oculta y muestra arriba PagerFragment . PagerFragment tiene un ViewPager y cada fragmento dentro del adaptador de buscapersonas simplemente muestra una etiqueta: este fragmento se llama DataFragment . La lista de etiquetas se crea en la actividad primaria y se pasa a PagerFragment y luego a través de su adaptador a cada DataFragment . El cambio de la visibilidad de PagerFragment se realiza sin problemas y, cada vez que se vuelve visible, muestra la etiqueta mostrada anteriormente.

La clave del problema: ¡ utilice Fragment#getChildFragmentManager() cuando esté creando el adaptador viewpager y no getFragmentManager!

Tal vez puedas comparar este proyecto simple con lo que tienes y comprobar dónde están las diferencias. Así que aquí va (de arriba hacia abajo):

PagerActivity (la única actividad en el proyecto):

public class PagerActivity extends FragmentActivity { private static final String PAGER_TAG = "PagerActivity.PAGER_TAG"; @Override protected void onCreate(Bundle savedInstance) { super.onCreate(savedInstance); setContentView(R.layout.pager_activity); if (savedInstance == null) { PagerFragment frag = PagerFragment.newInstance(buildPagerData()); FragmentManager fm = getSupportFragmentManager(); fm.beginTransaction().add(R.id.layout_fragments, frag, PAGER_TAG).commit(); } findViewById(R.id.btnFragments).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { changeFragmentVisibility(); } }); } private List<String> buildPagerData() { ArrayList<String> pagerData = new ArrayList<String>(); pagerData.add("Robert de Niro"); pagerData.add("John Smith"); pagerData.add("Valerie Irons"); pagerData.add("Metallica"); pagerData.add("Rammstein"); pagerData.add("Zinedine Zidane"); pagerData.add("Ronaldo da Lima"); return pagerData; } protected void changeFragmentVisibility() { Fragment frag = getSupportFragmentManager().findFragmentByTag(PAGER_TAG); if (frag == null) { Toast.makeText(this, "No PAGER fragment found", Toast.LENGTH_SHORT).show(); return; } boolean visible = frag.isVisible(); Log.d("APSampler", "Pager fragment visibility: " + visible); FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); if (visible) { ft.hide(frag); } else { ft.show(frag); } ft.commit(); getSupportFragmentManager().executePendingTransactions(); } }

su archivo de diseño pager_activity.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="4dp" > <Button android:id="@+id/btnFragments" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:text="Hide/Show fragments" /> <RelativeLayout android:id="@+id/layout_fragments" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/btnFragments" android:layout_marginBottom="4dp" > </RelativeLayout> </RelativeLayout>

Observe que estoy agregando el PagerFragment cuando la actividad se muestra por primera vez, y la clase PagerFragment :

public class PagerFragment extends Fragment { private static final String DATA_ARGS_KEY = "PagerFragment.DATA_ARGS_KEY"; private List<String> data; private ViewPager pagerData; public static PagerFragment newInstance(List<String> data) { PagerFragment pagerFragment = new PagerFragment(); Bundle args = new Bundle(); ArrayList<String> argsValue = new ArrayList<String>(data); args.putStringArrayList(DATA_ARGS_KEY, argsValue); pagerFragment.setArguments(args); return pagerFragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); data = getArguments().getStringArrayList(DATA_ARGS_KEY); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.pager_fragment, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { pagerData = (ViewPager) view.findViewById(R.id.pager_data); setupPagerData(); } private void setupPagerData() { PagerAdapter adapter = new LocalPagerAdapter(getChildFragmentManager(), data); pagerData.setAdapter(adapter); } }

su diseño (solo el ViewPager que toma tamaño completo):

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pager_data" android:layout_width="match_parent" android:layout_height="match_parent" />

y su adaptador:

public class LocalPagerAdapter extends FragmentStatePagerAdapter { private List<String> pagerData; public LocalPagerAdapter(FragmentManager fm, List<String> pagerData) { super(fm); this.pagerData = pagerData; } @Override public Fragment getItem(int position) { return DataFragment.newInstance(pagerData.get(position)); } @Override public int getCount() { return pagerData.size(); } }

Este adaptador crea un DataFragment para cada página:

public class DataFragment extends Fragment { private static final String DATA_ARG_KEY = "DataFragment.DATA_ARG_KEY"; private String localData; public static DataFragment newInstance(String data) { DataFragment df = new DataFragment(); Bundle args = new Bundle(); args.putString(DATA_ARG_KEY, data); df.setArguments(args); return df; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); localData = getArguments().getString(DATA_ARG_KEY); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.data_fragment, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { view.findViewById(R.id.btn_page_action).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(getActivity(), localData, Toast.LENGTH_SHORT).show(); } }); ((TextView) view.findViewById(R.id.txt_label)).setText(localData); } }

y el diseño de DataFragment :

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="4dp" > <Button android:id="@+id/btn_page_action" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:text="Interogate" /> <TextView android:id="@+id/txt_label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textAppearance="?android:attr/textAppearanceLarge" /> </RelativeLayout>

¡Disfruta la codificación!

He estado viendo un comportamiento extraño con mi ViewPager junto con mi propio FragmentStatePagerAdapter.

La jerarquía de mi vista es así:

-> (1) Fragment root view (RelativeLayout) -> (2) ViewPager -> (3) ViewPager''s current fragment view

Cuando el Fragmento que es responsable de la vista de raíz Fragmento (1) se oculta (usando .hide () en una transacción de fragmento) y luego se muestra (con .show ()), la vista de fragmento que se mostraba actualmente en ViewPager (3 ) se vuelve nulo, aunque el fragmento aún existe. Básicamente, mi ViewPager se vuelve completamente en blanco / transparente.

La única forma que he encontrado para solucionar esto es llamar

int current = myViewPager.getCurrentItem(); myViewPager.setAdapter(myAdapter); myViewPager.setCurrentItem(current);

después de que se muestre el fragmento principal. Esto de alguna manera activa las vistas para ser recreadas y aparecer en la pantalla. Desafortunadamente, esto ocasionalmente ocasiona excepciones relacionadas con el adaptador de buscapersonas que llama a unregisterDataSetObserver() dos veces en un viejo observador.

¿Hay una mejor manera de hacer esto? Creo que lo que estoy preguntando es:

¿Por qué mis vistas de fragmento dentro de mi ViewPager se destruyen cuando el fragmento principal de ViewPager está oculto?

Actualización: esto también ocurre cuando la aplicación se "minimiza" y luego se "restaura" (presionando la tecla de acción local y luego regresando).

Por solicitud, aquí está mi clase de adaptador de buscapersonas:

public class MyInfoSlidePagerAdapter extends FragmentStatePagerAdapter { private ArrayList<MyInfo> infos = new ArrayList<MyInfo>(); public MyInfoSlidePagerAdapter (FragmentManager fm) { super(fm); } public MyInfoSlidePagerAdapter (FragmentManager fm, MyInfo[] newInfos) { super(fm); setInfos(newInfos); } @Override public int getItemPosition(Object object) { int position = infos.indexOf(((MyInfoDetailsFragment)object).getMyInfo()); return position > 0 ? position : POSITION_NONE; } @Override public CharSequence getPageTitle(int position) { return infos.get(position).getName(); } @Override public Fragment getItem(int i) { return infos.size() > 0 ? MyInfoDetailsFragment.getNewInstance(infos.get(i)) : null; } @Override public int getCount() { return infos.size(); } public Location getMyInfoAtPosition(int i) { return infos.get(i); } public void setInfos(MyInfo[] newInfos) { infos = new ArrayList<MyInfo>(Arrays.asList(newInfos)); } public int getPositionOfMyInfo(MyInfo info) { return infos.indexOf(info); } }

He cambiado el nombre de algunas variables, pero aparte de eso, es exactamente lo que tengo.


Para mí cambié a getChildFragmentManager() lugar de getFragmentManager() y funciona bien. Ex:

pagerAdapt = new PagerAdapt(getChildFragmentManager());


View Pager es bastante firme en mantener sus Fragmentos frescos siempre y así optimizar el rendimiento al liberar memoria cuando no se usa un fragmento. Claramente, ese es un rasgo útil válido en un sistema móvil. Pero debido a esta desasignación persistente de recursos, el fragmento se crea cada vez que se enfoca.

mViewPager.setOffscreenPageLimit(NUMBEROFFRAGMENTSCREENS);

Aquí está la mViewPager.setOffscreenPageLimit(5)

este Old Post tiene una solución interesante para su problema. Consulte


Yo tuve el mismo problema. Mi aplicación (FragmentActivity) tiene un buscapersonas (ViewPager) con 3 framgents. Al deslizar entre los fragmentos, se destruyen y se vuelven a crear todo el tiempo. En realidad, no presenta ningún problema de funcionalidad (espere cursores no cerrados), pero también me preguntaba sobre esta cuestión.

No sé si hay una solución alternativa para cambiar el comportamiento de ViewPager, pero sugiero tener un objeto de configuración (quizás una estática myViewPager ) y antes de destruir guarde su objeto myViewPager en el objeto de configuración.

public class App extends FragmentActivity { static MyData data; @Override protected void onCreate(Bundle savedInstanceState) { data = (MyData) getLastCustomNonConfigurationInstance(); if (data == null) { data = new MyData(); data.savedViewPager = myViewPager; } else { myViewPager = data.savedViewPager; } } @Override public Object onRetainCustomNonConfigurationInstance() { Log.d("onRetainCustomNonConfigurationInstance", "Configuration call"); return data; } } public class MyData { public ViewPager savedViewPager; }

De esta forma, puede guardar la referencia al objeto que no se destruirá, por lo tanto, se hace referencia a él y puede volver a cargar todos sus objetos cruciales.

¡Espero que encuentres útil mi sugerencia!


tal vez ayude a mViewPager.setOffscreenPageLimit(5)

Establezca el número de páginas que deben conservarse en cualquier lado de la página actual en la jerarquía de vistas en un estado inactivo. Las páginas más allá de este límite se recrearán desde el adaptador cuando sea necesario.

Esto se ofrece como una optimización. Si sabe de antemano el número de páginas que necesitará para admitir o tiene instalados mecanismos de carga diferida en sus páginas, ajustar esta configuración puede tener beneficios en la suavidad percibida de las animaciones e interacciones de búsqueda. Si tiene un pequeño número de páginas (3-4) que puede mantener activo de una vez, se gastará menos tiempo en el diseño de los subárboles de vista recién creados a medida que el usuario va y viene.

Debe mantener este límite bajo, especialmente si sus páginas tienen diseños complejos. Esta configuración predeterminada es 1.