android methods android-viewpager onresume

Android ViewPager setCurrentItem no funciona después de onResume



methods android-viewpager (13)

Tengo este extraño problema, el SetCurrentItem de ViewPager (position, false) funciona perfectamente bien, luego estoy cambiando a otra actividad, y luego de volver a la primera actividad, el ViewPager siempre termina en el primer elemento. Aunque he agregado setCurrentItem al método onResume, todavía lo ignora. No está lanzando ninguna excepción cuando intento establecer el ítem fuera del índice de límites. Aunque más adelante cuando llamo a este método, cuando se hace clic en el botón "siguiente", funciona como se esperaba. Comprobé mi código 10 veces para cualquier posible llamada a setCurrentItem (0) o smth, pero simplemente no está allí en absoluto.


Debe llamar a pager.setCurrentItem (activePage) justo después de pager.setAdapter (buildAdapter ())

@Override public void onResume() { if (pager.getAdapter() != null) { activePage=pager.getCurrentItem(); Log.w(getClass().getSimpleName(), "pager.getAdapter()!=null"); pager.setAdapter(null); } pager.setAdapter(buildAdapter()); pager.setCurrentItem(activePage); }


En el momento en que llamo a setCurrentItem() la vista está a punto de ser recreada. De hecho, invoco setCurrentItem() para el viewpager y luego el sistema llama onCreateView() y crea un nuevo viewpager.

Esta es la razón por la que no veo ningún cambio. Y esta es la razón por la que un postDelayed() puede ayudar.

Solución teórica: setCurrentItem() invocación setCurrentItem() hasta que la vista haya sido recreada.

Solución práctica: no tengo idea de una solución estable y simple. Deberíamos poder verificar si la clase está a punto de recrear su vista y si ese es el caso posponer la invocación de setCurrentItem() al final de onCreateView()


Encontré una solución muy simple para esto:

if (mViewPager.getAdapter() != null) mViewPager.setAdapter(null); mViewPager.setAdapter(mPagerAdapter); mViewPager.setCurrentItem(desiredPos);

Y, si eso no funciona, puede ponerlo en un controlador, pero no hay necesidad de un retraso programado:

new Handler().post(new Runnable() { @Override public void run() { mViewPager.setCurrentItem(desiredPos); } });


Este es un problema de ciclo de vida, como lo señalan varios carteles aquí. Sin embargo, creo que las soluciones con la publicación de Runnable son impredecibles y probablemente propensas a errores. Parece una forma de ignorar el problema al publicarlo en el futuro.

No estoy diciendo que esta sea la mejor solución, pero definitivamente funciona sin usar Runnable . ViewPager un entero separado dentro del Fragment que tiene el ViewPager . Este número entero contendrá la página que queremos establecer como la página actual cuando onResume se llame a continuación. El valor del entero se puede establecer en cualquier punto y, por lo tanto, se puede establecer antes de una FragmentTransaction o al reanudar una actividad. También tenga en cuenta que todos los miembros están configurados en onResume() , no en onCreateView() .

public class MyFragment extends Fragment { private ViewPager mViewPager; private MyPagerAdapter mAdapter; private TabLayout mTabLayout; private int mCurrentItem = 0; // Used to keep the page we want to set in onResume(). @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.my_layout, container, false); mViewPager = (ViewPager) view.findViewById(R.id.my_viewpager); mTabLayout = (TabLayout) view.findViewById(R.id.my_tablayout); return view; } @Override public void onResume() { super.onResume(); MyActivity myActivity = (MyActivity) getActivity(); myActivity.getSupportActionBar().setTitle(getString(R.string.my_title)); mAdapter = new MyPagerAdapter(getChildFragmentManager(), myActivity); mViewPager.setAdapter(mAdapter); mViewPager.setOffscreenPageLimit(PagerConstants.OFFSCREEN_PAGE_LIMIT); mViewPager.setCurrentItem(mCurrentItem); // <-- Note the use of mCurrentItem here! mTabLayout.setupWithViewPager(mViewPager); } /** * Call this at any point before needed, for example before performing a FragmentTransaction. */ public void setCurrentItem(int currentItem) { mCurrentItem = currentItem; // This should be called in cases where onResume() is not called later, // for example if you only want to change the page in the ViewPager // when clicking a Button or whatever. Just omit if not needed. mViewPager.setCurrentItem(mCurrentItem); } }


He usado el método post () descrito aquí y estoy seguro de que funcionaba bien en algunos escenarios, pero como mis datos provienen del servidor, no era el santo grial.

Mi problema es que quiero tener

notifyDataSetChanged

llamado en un momento arbitrario y luego cambiar las pestañas en mi viewPager. Así que justo después de la llamada de notificación tengo esto

ViewUtilities.waitForLayout(myViewPager, new Runnable() { @Override public void run() { myViewPager.setCurrentItem(tabIndex , false); } });

y

public final class ViewUtilities { public static void waitForLayout(final View view, final Runnable runnable) { view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { //noinspection deprecation view.getViewTreeObserver().removeGlobalOnLayoutListener(this); runnable.run(); } }); } }

Dato curioso : // la desactivación de noinspection al final se debe a que hay un error de ortografía en la API que se corrigió después de API 16, por lo que debería leer remove On GlobalLayoutListener en lugar de removeGlobal en LayoutListener

Esto parece estar cubriendo todos los casos para mí.


Lo hice de esta manera para restaurar el elemento actual:

@Override protected void onSaveInstanceState(Bundle outState) { if (mViewPager != null) { outState.putInt(STATE_PAGE_NO, mViewPager.getCurrentItem()); } super.onSaveInstanceState(outState); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { if (savedInstanceState != null) { mCurrentPage = savedInstanceState.getInt(STATE_PAGE_NO, 0); } super.onRestoreInstanceState(savedInstanceState); } @Override protected void onRestart() { mViewPager.setCurrentItem(mCurrentPage); super.onRestart(); }


Para mí, esto funcionó estableciendo el elemento actual después de configurar el adaptador

viewPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager())); viewPager.setCurrentItem(idx); pagerSlidingTabStrip.setViewPager(viewPager);// assign viewpager to tabs


Tengo el mismo problema y edito

@Override public int getCount() { return NUM_PAGES; }

Establecí NUM_PAGES un error de solo 1.


Tuve un problema similar en OnCreate of my Activity. El adaptador se configuró con el recuento correcto y apliqué setCurrentItem después de configurar el adaptador en ViewPager; sin embargo, devolvería el índice fuera de límites. Creo que ViewPager no había cargado todos mis Fragmentos en el momento en que establecí el elemento actual. Al publicar un ejecutable en ViewPager, pude solucionar esto. Aquí hay un ejemplo con un poco de contexto.

// Locate the viewpager in activity_main.xml final ViewPager viewPager = (ViewPager) findViewById(R.id.pager); // Set the ViewPagerAdapter into ViewPager viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager())); viewPager.setOffscreenPageLimit(2); viewPager.post(new Runnable() { @Override public void run() { viewPager.setCurrentItem(ViewPagerAdapter.CENTER_PAGE); } });


Tuve una falla similar en el código, el problema fue que estaba configurando la posición antes de cambiar los datos.

La solución fue simplemente establecer el puesto luego y notificar que los datos habían cambiado

notifyDataSetChanged() setCurrentItem()


un tipo escribió en foros aquí. https://code.i-harness.com/en/q/126bff9 funcionó para mí

if (mViewPager.getAdapter() != null) mViewPager.setAdapter(null); mViewPager.setAdapter(mPagerAdapter); mViewPager.setCurrentItem(desiredPos);


LIMPIO Y SIMPLE No es necesario agregar el método de publicación simplemente setCurrentItem después de llamar notifyDataSetChanged ().


realmente no puedo responder POR QUÉ sucede exactamente esto, pero si retrasa la llamada setCurrentItem durante unos milisegundos debería funcionar. Supongo que porque durante onResume todavía no ha habido un pase de representación, y ViewPager necesita uno o algo así.

private ViewPager viewPager; @Override public void onResume() { final int pos = 3; viewPager.postDelayed(new Runnable() { @Override public void run() { viewPager.setCurrentItem(pos); } }, 100); }

ACTUALIZACIÓN: tiempo de la historia

así que hoy tuve el problema de que el viewpager ignoró mi acción setCurrentItem, y busqué una solución en . encontré a alguien con el mismo problema y una solución; Implementé la solución y no funcionó. ¡Whoa! de vuelta a para rechazar ese faux-fix-provider, y ...

fui yo. Implementé mi propia falla no corregida, que se me ocurrió la primera vez que tropecé con el problema (y que luego fue olvidado). ahora tendré que rechazar mi voto por proporcionar información incorrecta.

la razón por la que mi "corrección" inicial no funcionó debido a un "pase de representación"; el problema era que el contenido del buscapersonas estaba controlado por un girador. tanto los spinners como el estado de los buscapersonas se restauraron en Reesume, y debido a esto, se llamó al oyente spinners onItemSelected durante el siguiente ciclo de propagación del evento, que repobló al viewpager, esta vez usando un valor predeterminado diferente.
eliminar y restablecer el oyente durante la restauración de estado inicial solucionó el problema.

el arreglo anterior funcionaba la primera vez, porque configuraba la posición actual de los buscapersonas después de disparar el evento onItemSelected. más tarde, dejó de funcionar por alguna razón (probablemente la aplicación se volvió demasiado lenta; en mi implementación no usé 100 ms, sino 10 ms). Luego eliminé el mensaje Detenido en un ciclo de limpieza, porque no cambió el comportamiento ya defectuoso.

actualización 2: no puedo rechazar mi propia publicación. supongo, honorable seppuku es la única opción que queda.