No puedo actualizar el contenido en ViewPager.
¿Cuál es el uso correcto de los métodos instantiateItem () y getItem () en la clase FragmentPagerAdapter?
Estaba usando solo getItem () para crear instancias y devolver mis fragmentos:
@Override
public Fragment getItem(int position) {
return new MyFragment(context, paramters);
}
Esto funcionó bien. Excepto que no puedo cambiar el contenido.
Así que encontré esto: ViewPager PagerAdapter no actualiza la Vista
"Mi enfoque es utilizar el método setTag () para cualquier vista instanciada en el método instantiateItem ()"
Ahora quiero implementar instantiateItem () para hacer eso. Pero no sé qué debo devolver (el tipo es Object) y cuál es la relación con getItem (int position).
Leí la referencia :
Fragmento abstracto público getItem (posición int)
Devuelve el Fragmento asociado con una posición especificada.
objeto público instantiateItem (contenedor ViewGroup, posición int)
Crea la página para el puesto dado. El adaptador es responsable de agregar la vista al contenedor que se proporciona aquí, aunque solo debe asegurarse de que esto se haga para cuando regrese de finishUpdate (ViewGroup). Parámetros
contenedor La vista que contiene en la que se mostrará la página. posición La posición de la página que se instanciará.
Devoluciones
Devuelve un objeto que representa la nueva página. Esto no necesita ser una Vista, pero puede ser otro contenedor de la página.
Pero todavía no lo entiendo.
Aquí está mi código. Estoy usando el paquete de soporte v4.
ViewPagerTest
public class ViewPagerTest extends FragmentActivity {
private ViewPager pager;
private MyFragmentAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pager1);
pager = (ViewPager)findViewById(R.id.slider);
String[] data = {"page1", "page2", "page3", "page4", "page5", "page6"};
adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
pager.setAdapter(adapter);
((Button)findViewById(R.id.button)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
reload();
}
});
}
private void reload() {
String[] data = {"changed1", "changed2", "changed3", "changed4", "changed5", "changed6"};
//adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
adapter.setData(data);
adapter.notifyDataSetChanged();
pager.invalidate();
//pager.setCurrentItem(0);
}
}
MyFragmentAdapter
class MyFragmentAdapter extends FragmentPagerAdapter {
private int slideCount;
private Context context;
private String[] data;
public MyFragmentAdapter(FragmentManager fm, int slideCount, Context context, String[] data) {
super(fm);
this.slideCount = slideCount;
this.context = context;
this.data = data;
}
@Override
public Fragment getItem(int position) {
return new MyFragment(data[position], context);
}
@Override
public int getCount() {
return slideCount;
}
public void setData(String[] data) {
this.data = data;
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
MyFragment
public final class MyFragment extends Fragment {
private String text;
public MyFragment(String text, Context context) {
this.text = text;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.slide, null);
((TextView)view.findViewById(R.id.text)).setText(text);
return view;
}
}
Aquí también hay alguien con un problema similar, sin respuestas http://www.mail-archive.com/[email protected]/msg200477.html
Respuestas:
Al usar FragmentPagerAdapter o FragmentStatePagerAdapter, es mejor tratar solo
getItem()
y no tocarloinstantiateItem()
en absoluto. La interfazinstantiateItem()
-destroyItem()
-isViewFromObject()
en PagerAdapter es una interfaz de nivel inferior que FragmentPagerAdapter utiliza para implementar unagetItem()
interfaz mucho más simple .Antes de entrar en esto, debo aclarar que
Una versión anterior de esta respuesta cometió el error de usar FragmentPagerAdapter como ejemplo; eso no funcionará porque FragmentPagerAdapter nunca destruye un fragmento después de que se muestra por primera vez.
No recomiendo el
setTag()
y lafindViewWithTag()
solución proporcionada en el post se conectó. Como has descubierto, usarsetTag()
yfindViewWithTag()
no funciona con fragmentos, por lo que no es una buena combinación.La solución correcta es anular
getItemPosition()
. CuandonotifyDataSetChanged()
se llama, ViewPager llamagetItemPosition()
a todos los elementos en su adaptador para ver si necesitan ser movidos a una posición diferente o eliminados.Por defecto,
getItemPosition()
devuelvePOSITION_UNCHANGED
, lo que significa, "Este objeto está bien donde está, no lo destruya ni lo elimine". VolverPOSITION_NONE
soluciona el problema diciendo: "Este objeto ya no es un elemento que estoy mostrando, elimínelo". Por lo tanto, tiene el efecto de eliminar y recrear cada elemento de su adaptador.Esta es una solución completamente legítima! Esta solución hace que notifyDataSetChanged se comporte como un adaptador normal sin ver el reciclaje. Si implementa esta solución y el rendimiento es satisfactorio, está listo para las carreras. Trabajo hecho.
Si necesita un mejor rendimiento, puede usar una
getItemPosition()
implementación más sofisticada . Aquí hay un ejemplo para un buscapersonas que crea fragmentos a partir de una lista de cadenas:Con esta implementación, solo se mostrarán los fragmentos que muestran títulos nuevos. En cambio, cualquier fragmento que muestre títulos que todavía están en la lista se moverá a su nueva posición en la lista, y los fragmentos con títulos que ya no están en la lista serán destruidos.
¿Qué pasa si el fragmento no se ha recreado, pero necesita actualizarse de todos modos? Las actualizaciones de un fragmento vivo se manejan mejor con el fragmento mismo. Esa es la ventaja de tener un fragmento, después de todo, es su propio controlador. Un fragmento puede agregar un oyente u observador a otro objeto
onCreate()
y luego eliminarloonDestroy()
, administrando así las actualizaciones. No es necesario que coloque todo el código de actualizacióngetItem()
como lo hace en un adaptador para ListView u otros tipos de AdapterView.Una última cosa: solo porque FragmentPagerAdapter no destruye un fragmento no significa que getItemPosition sea completamente inútil en un FragmentPagerAdapter. Todavía puede usar esta devolución de llamada para reordenar sus fragmentos en ViewPager. Sin embargo, nunca los eliminará por completo del FragmentManager.
fuente
FragmentStatePagerAdapter
, puedo ver que elimina mi fragmento y crea la nueva instancia. Pero la nueva instancia recibe un Bundle de estado guardado con el estado de un fragmento antiguo. ¿Cómo puedo destruir completamente el fragmento para que Bundle sea nulo cuando se vuelva a crear?En lugar de regresar
POSITION_NONE
degetItemPosition()
y causando la vista de recreo, hacer esto:Sus fragmentos deben implementar la
UpdateableFragment
interfaz:y la interfaz:
Tu clase de datos:
fuente
Fragment
dinámicamente, eche un vistazo: stackoverflow.com/questions/19891828/…d page on refreshes the 1-st page only after swiping pages? thw 2
página 3 d siempre está en blanco. graciaspara aquellos que todavía enfrentan el mismo problema que enfrenté antes cuando tengo un
ViewPager
con 7 fragmentos. el valor predeterminado para estos fragmentos es cargar el contenido en inglés delAPI
servicio, pero el problema aquí es que quiero cambiar el idioma de la actividad de configuración y después de finalizar la actividad de configuración quieroViewPager
en la actividad principal actualizar los fragmentos para que coincidan con la selección de idioma del usuario y cargar el contenido en árabe si el usuario elige árabe aquí lo que hice para trabajar desde la primera vez1- Debe usar FragmentStatePagerAdapter como se mencionó anteriormente.
2- on mainActivity anulo el onResume e hice lo siguiente
3-
getItemPosition()
anulé el mPagerAdapter y lo devolvíPOSITION_NONE
.funciona como encanto
fuente
Encontré este problema y finalmente lo resolví hoy, así que escribo lo que he aprendido y espero que sea útil para alguien que es nuevo en Android
ViewPager
y actualice como lo hago. Estoy usandoFragmentStatePagerAdapter
API nivel 17 y actualmente solo tengo 2 fragmentos. Creo que debe haber algo incorrecto, corrígeme, gracias.Los datos serializados deben cargarse en la memoria. Esto se puede hacer usando un
CursorLoader
/AsyncTask
/Thread
. Si se carga automáticamente depende de su código. Si está utilizando unCursorLoader
, se carga automáticamente ya que hay un observador de datos registrado.Después de llamar
viewpager.setAdapter(pageradapter)
,getCount()
se llama constantemente al adaptador para construir fragmentos. Entonces, si se están cargando datos,getCount()
puede devolver 0, por lo que no necesita crear fragmentos ficticios para que no se muestren datos.Después de cargar los datos, el adaptador no generará fragmentos automáticamente ya
getCount()
que todavía es 0, por lo que podemos establecer el número de datos realmente cargado para que se devuelvagetCount()
y luego llamar al adaptadornotifyDataSetChanged()
.ViewPager
comenzar a crear fragmentos (solo los primeros 2 fragmentos) por datos en la memoria. Se hace antes de quenotifyDataSetChanged()
se devuelva. EntoncesViewPager
tiene los fragmentos correctos que necesita.Si los datos en la base de datos y la memoria se actualizan (escritura), o solo se actualizan los datos en la memoria (escritura), o solo se actualizan los datos en la base de datos. En los últimos dos casos, si los datos no se cargan automáticamente desde la base de datos a la memoria (como se mencionó anteriormente). El
ViewPager
adaptador de buscapersonas solo se ocupa de los datos en la memoria.Entonces, cuando se actualizan los datos en la memoria, solo necesitamos llamar al adaptador
notifyDataSetChanged()
. Como el fragmento ya está creado,onItemPosition()
se llamará al adaptador antes de quenotifyDataSetChanged()
regrese. No hay que hacer nadagetItemPosition()
. Luego se actualizan los datos.fuente
notifyDataSetChanged()
luego simplemente actualice automáticamente, porque el fragmento (con vista de gráfico) que uso se actualizará. si no es así, como un fragmento estático, tendré que llamaronItemPositon()
y devolver loPOSITION_NONE
siento por esoProbar
destroyDrawingCache()
en ViewPager despuésnotifyDataSetChanged()
en su código.fuente
Fragments
mi localizador de vistas. ¡Así que gracias!Después de horas de frustración mientras intentaba todas las soluciones anteriores para superar este problema y también intentaba muchas soluciones en otras preguntas similares como esta , esto y esto que me FALLÓ para resolver este problema y hacer
ViewPager
que destruya lo viejoFragment
y lo llenepager
de el nuevoFragment
s. He resuelto el problema de la siguiente manera:1) Haga que la
ViewPager
clase se extienda de laFragmentPagerAdapter
siguiente manera:2) Cree un artículo para el
ViewPager
que almacena eltitle
y elfragment
siguiente:3) Haga que el constructor de
ViewPager
take myFragmentManager
instance lo almacene en mi de laclass
siguiente manera:4) Crear un método para re-establecer los
adapter
datos con los nuevos datos mediante la supresión de todos los anterioresfragment
de lafragmentManager
misma directamente a hacer eladapter
para establecer la nuevafragment
de la nueva lista de nuevo de la siguiente manera:5) Desde el contenedor
Activity
oFragment
no reinicialice el adaptador con los nuevos datos. Establezca los nuevos datos a través del métodosetPagerItems
con los nuevos datos de la siguiente manera:Espero que ayude.
fuente
Por alguna razón, ninguna de las respuestas funcionó para mí, así que tuve que anular el método restoreState sin llamar a super en mi fragmentStatePagerAdapter. Código:
fuente
Modifiqué ligeramente la solución provista por Bill Phillips para satisfacer mis necesidades
para que solo se
getItemPosition()
devuelvanPOSITION_NONE
los fragmentos que se encuentran actualmente en elFragmentManager
momento en quegetItemPosition
se llama. (Tenga en cuenta que estoFragmentStatePager
y loViewPager
asociado con él están contenidos en un Fragmento no en una Actividad)fuente
Tuve un problema similar pero no quiero confiar en las soluciones existentes (nombres de etiquetas codificadas, etc.) y no pude hacer que la solución de M-WaJeEh funcionara para mí. Aquí está mi solución:
Mantengo referencias a los fragmentos creados en getItem en una matriz. Esto funciona bien siempre que la actividad no se destruya debido a un cambio de configuración o falta de memoria o lo que sea (-> al volver a la actividad, los fragmentos vuelven a su último estado sin que se vuelva a llamar a 'getItem' y, por lo tanto, sin actualizar la matriz )
Para evitar este problema, implementé instantiateItem (ViewGroup, int) y actualicé mi matriz allí, así:
Entonces, por un lado, estoy feliz de haber encontrado una solución que funciona para mí y quería compartirla con ustedes, pero también quería preguntar si alguien más intentó algo similar y si hay alguna razón por la que no debería hazlo asi? Hasta ahora funciona muy bien para mí ...
fuente
myFragments
enpublic void destroyItem(ViewGroup container, int position, Object object)
para que no tomes una referencia de material obsoleto.Yo uso la biblioteca EventBus para actualizar el
Fragment
contenidoViewPager
. La lógica es simple, al igual que el documento de EventBus cómo hacerlo . No es necesario controlar laFragmentPagerAdapter
instancia. El código está aquí:1: definir eventos
Defina qué mensaje se necesita para actualizar.
2.Preparar suscriptores
Escriba a continuación el código en el Fragmento que se necesita actualizar.
3. Eventos posteriores
Escriba el siguiente código en otro
Activity
u otroFragment
que necesite actualizar el parámetrofuente
Si desea utilizar FragmentStatePagerAdapter, consulte https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary% 20 Estrellas y grupoby = & sort = & id = 37990 . Hay problemas con FragmentStatePagerAdapter que pueden o no causar problemas en su caso de uso.
Además, el enlace también tiene pocas soluciones ... pocas pueden adaptarse a sus necesidades.
fuente
He vivido el mismo problema y he buscado demasiadas veces. Cualquier respuesta dada en stackoverflow o vía google no fue la solución para mi problema. Mi problema fue fácil. Tengo una lista, muestro esta lista con el visor. Cuando agrego un nuevo elemento al encabezado de la lista y actualizo el visor, nada cambió. Mi solución final fue muy fácil, cualquiera puede usarla. Cuando se agrega un nuevo elemento a la lista y desea actualizar la lista. Primero configure el adaptador del visor en nulo, luego vuelva a crear el adaptador y configúrelo en el visor.
Asegúrese de que su adaptador debe extender FragmentStatePagerAdapter
fuente
Aquí está mi implementación que incorpora la información de @Bill Phillips One obtiene el almacenamiento en caché de fragmentos la mayor parte del tiempo, excepto cuando los datos han cambiado. Simple, y parece funcionar bien.
MyFragmentStatePagerAdapter.java
MyActivity.java
fuente
Había estado probando tantos enfoques diferentes, ninguno realmente solucionó mi problema. A continuación se muestra cómo lo resuelvo con una combinación de soluciones proporcionadas por todos ustedes. Gracias a todos.
Solo quiero actualizar la página 0 después de onResume ().
En mi FragmentsMain, hay una "página" entera pública, que me puede decir si es la página que quiero actualizar.
fuente
Sé que llego tarde a la fiesta. He solucionado el problema llamando
TabLayout#setupWithViewPager(myViewPager);
justo despuésFragmentPagerAdapter#notifyDataSetChanged();
fuente
Esta solución no funcionará para todos, pero en mi caso, cada Fragmento en mi ViewPager es una clase diferente, y solo una de ellas existe a la vez.
Con esta restricción, esta solución es segura y debe ser segura de usar en la producción.
Si tiene varias versiones del mismo fragmento, puede usar esta misma estrategia para llamar a métodos en esos fragmentos para determinar si es el fragmento que desea actualizar.
fuente
Esto podría ser de ayuda para alguien: en mi caso, al insertar una nueva página, el localizador de vistas solicitaba la posición de un fragmento existente dos veces, pero no solicitaba la posición del nuevo elemento, lo que causaba un comportamiento incorrecto y no se mostraban los datos.
Copie la fuente de FragmentStatePagerAdapter (parece que no se ha actualizado en años).
Anular notifyDataSetChanged ()
Agregue una comprobación de cordura para destroyItem () para evitar bloqueos:
fuente
Revisé todas las respuestas anteriores y algunas otras publicaciones, pero aún no pude encontrar algo que funcionó para mí (con diferentes tipos de fragmentos junto con la adición y eliminación dinámica de pestañas). El siguiente enfoque de FWIW es lo que funcionó para mí (en caso de que alguien más tenga los mismos problemas).
fuente
Use FragmentStatePagerAdapter en lugar de FragmentPagerAdapter si desea volver a crear o recargar un fragmento en función del índice. Por ejemplo, si desea recargar un fragmento que no sea FirstFragment, puede verificar la instancia y devolver la posición de esta manera
fuente
Necesita cambiar el elemento getItemPosition de instantiateItem's mFragments.
Basado en AndroidX FragmentStatePagerAdapter.java, porque
mFragments
la posición de los elementos no cambia al llamar a notifyDataSetChanged ().Fuente: https://github.com/cuichanghao/infivt/blob/master/library/src/main/java/cc/cuichanghao/library/FragmentStatePagerChangeableAdapter.java
Ejemplo: https://github.com/cuichanghao/infivt/blob/master/app/src/main/java/cc/cuichanghao/infivt/MainActivityChangeablePager.kt
Puede ejecutar este proyecto para confirmar cómo funciona. https://github.com/cuichanghao/infivt
fuente