El fragmento en ViewPager que usa FragmentPagerAdapter está en blanco la segunda vez que se ve

98

Tengo una interfaz de fragmentos con pestañas en la parte inferior que abren diferentes fragmentos en la vista principal.

Tengo un fragmento particular que es una lista de elementos. Si el usuario selecciona uno de los elementos de esta lista, se abre otro fragmento que contiene un visor que se desplaza horizontalmente entre todos los elementos de la lista del fragmento anterior. Esto funciona muy bien.

El visor usa un FragmentPagerAdapter para mostrar los elementos.

El problema surge cuando el usuario selecciona un elemento de la lista, lo ve, luego presiona el botón en la barra de pestañas para volver a la lista y luego selecciona otro elemento. La segunda vez que se selecciona un elemento, aparece una pantalla en blanco en lugar del visor. No recibo ningún error en mi LogCat cuando esto sucede.

¿Por qué el visor solo aparece la primera vez?

FragmentPagerAdapter:

public class ViewPagerAdapter extends FragmentPagerAdapter {
    Cursor mCursor;

    public ViewPagerAdapter(FragmentManager fm, Cursor c) {
        super(fm);
        mCursor = c;
    }

    public void changeCursor(Cursor c) {
        mCursor = c;
        this.notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        if (mCursor == null) return 0;
        else return mCursor.getCount();
    }

    @Override
    public Fragment getItem(int position) {
        mCursor.moveToPosition(position);
        return TeamCardFragment.newInstance(mCursor, position);
    }
}

PagerFragment:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);

    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);

    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();

    return mView;
}

private class setAdapterTask extends AsyncTask<Void, Void, Void> {
    protected Void doInBackground(Void... params) {
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        mViewPager.setAdapter(mAdapter);
        mViewPager.setCurrentItem(mCursorPosition);
    }
}
Howettl
fuente

Respuestas:

221

Tuve el mismo problema. ¡Cambiando la clase principal de mi PageAdapter de android.support.v4.app.FragmentPagerAdapterpara android.support.v4.app.FragmentStatePagerAdapterresolver mi ViewPagerproblema de visualización en "segunda vez"!

Yann
fuente
2
¿En serio? Ya no tengo este código, de lo contrario lo probaría. Quizás esta respuesta ayude a alguien más.
howettl
10
¡Que hombre! ¡Estuve buscando esta solución durante días! Muchas gracias, hombre, funciona de maravilla. Pero el desarrollador que hay en mí se pregunta qué impacto tiene ese cambio. Me refiero a por qué no funcionó antes y por qué en StatePagerAdapter
Anand Sainath
1
también necesita @Override public int getItemPosition (Object object) {return POSITION_NONE; }
Helin Wang
1
También funcionó para mí. Aquí hay un enlace. Parece salvar el estado de fragmento, lo que marca la diferencia. developer.android.com/reference/android/support/v4/app/…
Tjaart
1
Es una coincidencia que esto funcione, la respuesta correcta es la de @Daniel F. De todos modos, para conveniencia de los comentaristas aquí, la diferencia entre FragmentPagerAdaptery FragmentStatePagerAdapteres que el primero es más adecuado para pocas páginas, retiene todos los fragmentos en la memoria, por lo que tiene el mejor rendimiento en el cambio de página, mientras que el segundo es más adecuado para muchas páginas. páginas, destruye fragmentos, manteniendo solo su estado, es más eficiente en memoria pero un poco más lento en el cambio de página.
Cristina De Rito
87

Me las arreglé para resolver esto reemplazando getFragmentManager()con getChildFragmentManager()en el fragmento principal. Este fragmento principal estaba instalando un android.support.v4.app.FragmentPagerAdapter para contener fragmentos paginables (deslizables), lo que requiere un administrador de fragmentos en el constructor. A este constructor pasé el valor de retorno de getChildFragmentManager().

El enlace de hackbod era clave ( https://developer.android.com/about/versions/android-4.2.html#NestedFragments ), que se encontró en esta publicación Fragmentos dentro de Fragmentos

Para anidar un fragmento, simplemente llame getChildFragmentManager()al Fragmento en el que desea agregar un fragmento. Esto devuelve un FragmentManager que puede usar como lo hace normalmente desde la actividad de nivel superior para crear transacciones de fragmentos.

Daniel F
fuente
Gracias ... estaba teniendo un problema similar al intentar volver a crear una instancia de una vista de pestañas deslizantes después de onresume () que contenía un fragmentpageradapter ... el tutorial que usé era de 2016 y todavía necesitaba cambiarlo a fragmentstatepageradapter para hacerlo trabajo. Ojalá supiera POR QUÉ.
Nerdy Bunz
esta respuesta me ahorró mucho tiempo. Porque solo usar no FragmentStatePagerAdapterresuelve la pregunta que se hace aquí. junto con el FragmentStatePagerAdapterfragmento principal YourAdapter adapter = new YourAdapter (getChildFragmentManager()); debe agregarse
MMK
17

para mí tuve que llamar a esto en mi visor:

myViewPager.setSaveFromParentEnabled(false);

Tuve el problema de que el visor no se actualizaba y todo lo que vi fue una pantalla en blanco donde deberían estar los fragmentos. Estaba pasando getChildFragmentManager pero no ayudó.

j2emanue
fuente
1
¿Por qué demonios funcionó esto? Esto solucionó mi problema, pero no tengo ni idea de por qué.
ClayHerendeen
Lo eliminé de mi código ahora. El administrador de fragmentos estaba causando el problema. Intente alternar entre getchildfragmentmanager y getfragmentmanager
j2emanue
Ya lo he probado. He anidado pestañas, cada una con ViewPagers que han desactivado el deslizamiento. Sé que este es un diseño deficiente, pero los deseos de los clientes no son míos. Estoy usando childFragmentManager para la barra de pestañas de nivel superior. Alternar para la barra de pestañas / visor de nivel inferior no pareció solucionar el problema. Supongo que me quedaré con setSaveFromParentEnabled (false) por ahora, ya que está funcionando.
ClayHerendeen
¿Está utilizando la última biblioteca de soporte?
j2emanue
2
Estaba enfrentando el mismo problema de los últimos 2 días. Su solución funcionó para mí. Gracias !
brijexecon
11

En mi caso muy particular, donde estaba usando un CoordinatorLayout con un AppBarLayout y el ViewPager, lo que me resolvió fue eliminar el android: fitSystemWindows = "true" de mis propiedades xml de AppBarLayout .

No me preguntes por qué. Sé que suena un poco ridículo y que no debería tener correlación, pero era esta única línea lo único que estaba causando problemas, ya que ya estaba usando getChildFragmentManager () en mi adaptador. Pasé un día entero depurando mi código solo para encontrar esto, así que espero que le ahorre algo de tiempo a alguien más.

emirua
fuente
3
Oh hombre ... casi me iba a rendir con este problema. ¡Hiciste mi maldito día! Caray Google, ¿WTF está mal con AppBarLayout? Miré casi cien páginas y pasé un montón de horas depurando tratando de resolver este problema sin suerte. Estoy realmente agradecido de que finalmente haya logrado resolver el problema con tu comentario. ¡Muchas gracias! PD: Estaba tan desesperado que incluso creé un problema en el AOSP: code.google.com/p/android/issues/… XD
Guillem Roca
Gracias por la pista. Al menos nos ha ayudado a resolver el problema. Ahora estamos tratando de encontrar la opción para hacerlo en pantalla completa
Paresh Mayani
¡Eres un salvavidas! ¡No tenía ni idea de por qué tenía este problema y aún no tenía ni idea de por qué funcionaba!
nandu
10

Yo tenía el mismo problema para el que he cambiado adaptador de FragmentPagerAdaptera FragmentStatePagerAdaptery getFragmentManager()en el fragmento de padres agetChildFragmentManager()

La razón detrás de esto es que FragmentStatePagerAdapteres útil para almacenar una gran cantidad de páginas y la memoria asociada con cada página visitada es menor, ya que solo mantiene el estado guardado del fragmento mientras la página no está visible. Esto reduce la sobrecarga al cambiar entre los fragmentos.

Yashaswi NP
fuente
4

Intente poner setOffscreenPageLimit (int limit)el ViewPager principal.

mViewPager.setOffscreenPageLimit(totalPages-1);

Esto funcionó para mí a las mil maravillas.

En mi caso tenía un fragmento dentro TabLayoutconViewPager.

Y otro ViewPagerdentro de ese fragmento. La primera vez todo funciona bien, pero cuando cambio de pestaña y regreso, parte de mi fragmento se quedó en blanco.

Rumit Patel
fuente
1
Buena respuesta. Me ha ayudado.
Thirumalvalavan
2

Esto te ayudaría.

    viewPager.setOffscreenPageLimit(position);
Pardeep Singh
fuente
1

Solucionamos esto volviendo a implementar los elementos del paginador de vistas como vistas estándar en lugar de fragmentos y cambiando el adaptador en consecuencia.

Howettl
fuente
puede intentar eliminar la función isViewFromObject (Ver vista, Objeto objeto)
Mina Samy
Tiene que haber una forma mejor ....: / aunque cuanto más profundizo en Android, menos maduro me doy cuenta de que es.
StackOverflowed
1
Los fragmentos anidados no son compatibles , por lo que volver a implementar con la vista estándar parece el buen camino a seguir.
Sylphe
Estoy luchando con un problema similar. Intenté usar PagerAdapter en lugar de FragmentAdapter, pero todavía encuentro el mismo problema. Por favor, ayúdame !
Gaurav Arora
Si desea usar fragmentos anidados, puede usar el adaptador que proporcioné en esta respuesta: stackoverflow.com/questions/7700226/…
Slickelito
1

Estaba teniendo este mismo problema en Xamarin Android con una pantalla en blanco la segunda vez. La configuración de lo siguiente lo solucionó.

viewPager.SaveFromParentEnabled = false;
Gerard
fuente
0

También puede inicializar el adaptador para los casos en los que experimente este error cuando su aplicación se minimice y luego se invoque.

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);
    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);
    initViewPagerAdapter();
    return mView;
}
private void initViewPagerAdapter(){
    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();
}

@Override
public void onResume(){
    super.onResume();
    initViewPagerAdapter();
}
Patricio
fuente
0

Tuve lo mismo, en la segunda vez que llamo al Adaptador de buscapersonas, la vista secundaria devuelve una NullPointerException. Y cambiar el adaptador en FragmentStatePagerAdapter también resuelve mi problema.

Arka-57
fuente
0

Cambiar FragmentPagerAdaptera FragmentStatePagerAdapter uso en getChildFragmentManager()lugar degetFragmentManager()

getChildFragmentManager()- porque de acuerdo con la documentación, devolverá un FragmentManager privado para colocar y administrar Fragmentos dentro de este Fragmento. Mientras tanto getFragmentManager(), devolverá el FragmentManager para interactuar con los fragmentos asociados con esta actividad.

Mostafa Anter
fuente
0

class ViewPagerAdapter extiende FragmentStatePagerAdapter este trabajo para mí prueba esto

Abdul Basit Abbasi
fuente