android - studio - reutilizando fragmentos en un fragmento páginaradapter
java android fragment (5)
Apéndice para la publicación de Geoff:
Puede obtener una referencia a su Fragment
en FragmentPagerAdapter
usando findFragmentByTag()
. El nombre de la etiqueta se genera de esta manera:
private static String makeFragmentName(int viewId, int index)
{
return "android:switcher:" + viewId + ":" + index;
}
donde viewId es id de ViewPager
Mire este enlace: http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/android/support/v2/app/FragmentPagerAdapter.java#104
Tengo un visor que páginas a través de fragmentos. Mi subclase FragmentPagerAdapter
crea un nuevo fragmento en el método getItem
que parece un desperdicio. ¿Existe un FragmentPagerAdapter
equivalente a convertView
en listAdapter
que me permita reutilizar fragmentos que ya se han creado? Mi código está abajo.
public class ProfilePagerAdapter extends FragmentPagerAdapter {
ArrayList<Profile> mProfiles = new ArrayList<Profile>();
public ProfilePagerAdapter(FragmentManager fm) {
super(fm);
}
/**
* Adding a new profile object created a new page in the pager this adapter is set to.
* @param profile
*/
public void addProfile(Profile profile){
mProfiles.add(profile);
}
@Override
public int getCount() {
return mProfiles.size();
}
@Override
public Fragment getItem(int position) {
return new ProfileFragment(mProfiles.get(position));
}
}
El FragmentPagerAdapter
ya almacena en caché los Fragments
por ti. A cada fragmento se le asigna una etiqueta, y luego el FragmentPagerAdapter
intenta llamar a findFragmentByTag
. Solo llama a getItem
si el resultado de findFragmentByTag
es null
. Entonces no deberías tener que almacenar los fragmentos tú mismo.
Parece que muchas de las personas que ven esta pregunta están buscando una forma de referenciar los Fragments
creados por FragmentPagerAdapter
/ FragmentStatePagerAdapter
. Me gustaría ofrecer mi solución a esto sin depender de las tags
creadas internamente que usan las otras respuestas aquí.
Como extra, este método también debería funcionar con FragmentStatePagerAdapter
. Vea las notas a continuación para obtener más detalles.
Problema con las soluciones actuales: confiar en el código interno
Muchas de las soluciones que he visto en esta y otras preguntas similares se basan en obtener una referencia al Fragment
existente llamando a FragmentManager.findFragmentByTag()
e imitando la etiqueta creada internamente: "android:switcher:" + viewId + ":" + id
. El problema con esto es que estás confiando en el código fuente interno, que, como todos sabemos, no se garantiza que permanezca igual para siempre. Los ingenieros de Android en Google podrían decidir cambiar la estructura de las tag
, lo que rompería su código y no podría encontrar una referencia a los Fragments
existentes.
Solución alternativa sin depender de la tag
interna
Aquí hay un ejemplo simple de cómo obtener una referencia a los Fragments
devueltos por FragmentPagerAdapter
que no depende de las tags
internas establecidas en los Fragments
. La clave es anular instantiateItem()
y guardar referencias allí en lugar de en getItem()
.
public class SomeActivity extends Activity {
private FragmentA m1stFragment;
private FragmentB m2ndFragment;
// other code in your Activity...
private class CustomPagerAdapter extends FragmentPagerAdapter {
// other code in your custom FragmentPagerAdapter...
public CustomPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
// Do NOT try to save references to the Fragments in getItem(),
// because getItem() is not always called. If the Fragment
// was already created then it will be retrieved from the FragmentManger
// and not here (i.e. getItem() won''t be called again).
switch (position) {
case 0:
return new FragmentA();
case 1:
return new FragmentB();
default:
// This should never happen. Always account for each position above
return null;
}
}
// Here we can finally safely save a reference to the created
// Fragment, no matter where it came from (either getItem() or
// FragmentManger). Simply save the returned Fragment from
// super.instantiateItem() into an appropriate reference depending
// on the ViewPager position.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// save the appropriate reference depending on position
switch (position) {
case 0:
m1stFragment = (FragmentA) createdFragment;
break;
case 1:
m2ndFragment = (FragmentB) createdFragment;
break;
}
return createdFragment;
}
}
public void someMethod() {
// do work on the referenced Fragments, but first check if they
// even exist yet, otherwise you''ll get an NPE.
if (m1stFragment != null) {
// m1stFragment.doWork();
}
if (m2ndFragment != null) {
// m2ndFragment.doSomeWorkToo();
}
}
}
o si prefiere trabajar con tags
lugar de variables de miembro de clase / referencias a los Fragments
, también puede tomar las tags
establecidas por FragmentPagerAdapter
de la misma manera: NOTA: esto no se aplica a FragmentStatePagerAdapter
ya que no establece tags
al crear sus Fragments
.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// get the tags set by FragmentPagerAdapter
switch (position) {
case 0:
String firstTag = createdFragment.getTag();
break;
case 1:
String secondTag = createdFragment.getTag();
break;
}
// ... save the tags somewhere so you can reference them later
return createdFragment;
}
Tenga en cuenta que este método NO se basa en imitar la tag
interna establecida por FragmentPagerAdapter
y en su lugar utiliza las API adecuadas para recuperarlos. De esta forma, incluso si la tag
cambia en futuras versiones de SupportLibrary
, estará a salvo.
No olvide que, dependiendo del diseño de su Activity
, los Fragments
que está tratando de trabajar pueden o no existir aún, por lo que tiene que dar cuenta de ello haciendo comprobaciones null
antes de usar sus referencias.
Además, si en su lugar está trabajando con FragmentStatePagerAdapter
, entonces no desea mantener referencias difíciles a sus Fragments
porque podría tener muchos de ellos y las referencias difíciles los mantendrían innecesariamente en la memoria. En su lugar, guarde las referencias al Fragment
en WeakReference
variables WeakReference
en lugar de las estándar. Me gusta esto:
WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
// ...and access them like so
Fragment firstFragment = m1stFragment.get();
if (firstFragment != null) {
// reference hasn''t been cleared yet; do work...
}
Sé que esto (teóricamente) no es una respuesta a la pregunta, sino un enfoque diferente.
Tuve un problema donde necesitaba actualizar los fragmentos visibles. Todo lo que probé, falló y falló miserablemente ...
Después de probar tantas cosas diferentes, finalmente termino usando BroadCastReceiver
. Simplemente envíe una transmisión cuando necesite hacer algo con los fragmentos visibles y capture en el fragmento.
Si necesita algún tipo de respuesta también, también puede enviarlo a través de la transmisión.
aclamaciones
Si el fragmento aún está en la memoria, puede encontrarlo con esta función.
public Fragment findFragmentByPosition(int position) {
FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
return getSupportFragmentManager().findFragmentByTag(
"android:switcher:" + getViewPager().getId() + ":"
+ fragmentPagerAdapter.getItemId(position));
}
Código de muestra para v4 support api.