OnResume () no se llama al fragmento ViewPager cuando se utiliza Custom Loader
Version corta:
Tengo un fragmento que mantiene un ViewPager
para mostrar otros dos fragmentos, llamémoslos FragmentOne
y FragmentTwo
. Cuando se inicia la aplicación FragmentOne
es visible y FragmentTwo
está fuera de la pantalla, haciéndose visible sólo cuando uno desliza la vista hacia la izquierda.
- La recreación de fragmentos de ViewPager se reanuda pero no se ve
- Cómo conservar el estado de ViewPager dentro de un RecyclerView?
- ¿Por qué ViewPager y GridLayout con 30 elementos son muy lentos?
- Cómo usar Android ViewPager
- Viewpager setCurrentItem no cambiar tablayout seleccionado color
Normalmente onStart()
y onResume()
se invocan inmediatamente para ambos fragmentos tan pronto como se inicie la aplicación.
El problema que tengo es cuando FragmentOne
inicia un Loader
personalizado, entonces onResume()
no se llama a FragmentTwo
hasta que se hace completamente visible.
Preguntas:
¿Es este un problema con mi código o un error en la Biblioteca de soporte de Android? (El problema no ocurrió con la revisión 12 de la biblioteca, que comenzó con la revisión 13.)
Si se trata de un error en las revisiones 13 y 18, ¿existe alguna solución?
¿Hay algo mal con mi Loader
personalizado?
Versión larga:
He construido una aplicación de ejemplo que demuestra el problema. He intentado reducir el código al mínimo pero todavía es mucho así que por favor tenga paciencia conmigo.
Tengo una MainActivity
que carga un MainFragment
que crea un ViewPager
. Es importante para mi aplicación que el ViewPager sea mantenido por un Fragmento en lugar de una Actividad.
MainFragment
crea un FragmentPagerAdapter
que a su vez crea los fragmentos FragmentOne
y FragmentTwo
.
Empecemos con el fragmento interesante, los dos fragmentos:
FragmentOne
es un ListFragment
que utiliza un Loader
personalizado para cargar el contenido:
public class FragmentOne extends ListFragment implements LoaderCallbacks<List<String>> { private ArrayAdapter<String> adapter; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1); setListAdapter(adapter); setEmptyText("Empty"); } @Override public void onResume() { super.onResume(); // initializing the loader seems to cause the problem! getLoaderManager().initLoader(0, null, this); } @Override public Loader<List<String>> onCreateLoader(int id, Bundle args) { return new MyLoader(getActivity()); } @Override public void onLoadFinished(Loader<List<String>> loader, List<String> data) { adapter.clear(); adapter.addAll(data); } @Override public void onLoaderReset(Loader<List<String>> loader) { adapter.clear(); } public static class MyLoader extends AsyncTaskLoader<List<String>> { public MyLoader(Context context) { super(context); } @Override protected void onStartLoading() { forceLoad(); } @Override public List<String> loadInBackground() { return Arrays.asList("- - - - - - - - - - - - - - - - - - - foo", "- - - - - - - - - - - - - - - - - - - bar", "- - - - - - - - - - - - - - - - - - - baz"); } } }
Es ese Loader
que parece causar el problema. Comentar la línea initLoader hace que el ciclo de vida del fragmento funcione de nuevo como se esperaba.
FragmentTwo
cambia su contenido basado en si onResume()
ha sido invocado o no:
public class FragmentTwo extends Fragment { private TextView text; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { text = new TextView(container.getContext()); text.setText("onCreateView() called"); return text; } @Override public void onResume() { super.onResume(); Log.i("Fragment2", "onResume() called"); text.setText("onResume() called"); } }
Y aquí está el resto aburrido del código.
MainActivity
:
public class MainActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Fragment fragment = new MainFragment(); getSupportFragmentManager().beginTransaction().add(R.id.container, fragment).commit(); } }
Layout activity_main
:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" />
MainFragment
:
public class MainFragment extends Fragment { private ViewPager viewPager; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View layout = inflater.inflate(R.layout.frag_master, container, false); viewPager = (ViewPager) layout.findViewById(R.id.view_pager); return layout; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); viewPager.setAdapter(new MyPagerAdapter(getChildFragmentManager())); } private static final class MyPagerAdapter extends FragmentPagerAdapter { public MyPagerAdapter(FragmentManager fragmentManager) { super(fragmentManager); } @Override public int getCount() { return 2; } @Override public Fragment getItem(int position) { if (position == 0) return new FragmentOne(); else return new FragmentTwo(); } } }
Diseño: frag_master
:
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent" />
- NullPointerException al mostrar un ViewPager una segunda vez
- Animación de visor de Android
- Fragmento Reemplazar con ViewPager en la pestaña ActionBar
- ¿Cómo puedo añadir un fragmento a un ViewPager? AddView bloquea mi aplicación
- Android.support.v4.app.FragmentManager y android.app.FragmentManager en ViewPager
- Android - FAB para ocultar al navegar entre diferentes fragmentos en un viewpager
- Manejo simultáneo de eventos táctiles en varias vistas en Android
- Android Viewpager tinder como UI con la apariencia de la pila de tarjetas 3D
Parece ser un error en la biblioteca de soporte. El cambio a continuación resuelve el problema.
// FragmentOne.java @Override public void onResume() { super.onResume(); Handler handler = getActivity().getWindow().getDecorView().getHandler(); handler.post(new Runnable() { @Override public void run() { // initialize the loader here! getLoaderManager().initLoader(0, null, FragmentOne.this); } }); }
Otra solución que funcionó para mí fue usar el gestor de cargador del MainFragment:
getParentFragment().getLoaderManager().initLoader(0, null, this);
- Android – teléfono construido en herramientas para desarrolladores – "Show Cpu Usage" opción significado?
- Cardview no respeta el orden del índice z en el diseño relativo