practice - Android FragmentStatePagerAdapter
viewpager in fragment (5)
Estoy trabajando con un FragmentStatePagerAdapter usando este ejemplo .
La clase MyAdapter se implementa de la siguiente manera:
public static class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return NUM_ITEMS;
}
@Override
public Fragment getItem(int position) {
return ArrayListFragment.newInstance(position);
}
}
La clase ListFragment incluye el siguiente método para crear una nueva instancia:
/**
* Create a new instance of CountingFragment, providing "num"
* as an argument.
*/
static ArrayListFragment newInstance(int num) {
ArrayListFragment f = new ArrayListFragment();
// Supply num input as an argument.
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
Cuando creo un nuevo adaptador de buscapersonas de estado de fragmento en mi actividad, se llama a getItem
, que a su vez llama al método newInstance
en la clase ListFragment. Esto es genial cuando quiero crear un nuevo fragmento.
Pero no me queda claro cómo modificar getItem
(si es necesario) para obtener el objeto de fragmento cuando ya existe y las páginas de usuario, por ejemplo, de la página 2 a la página 1. Me gustaría que mi Actividad recupere esa información existente, fragmento creado anteriormente para que pueda ejecutar una clase interna AsyncMethod
, que reside en la clase de fragmento.
Creo que la solución es mucho más simple que las respuestas proporcionadas.
Si echa un vistazo a la fuente de FragmentStatePagerAdapter.instantiateItem()
, notará que instantiateItem()
maneja esta lógica por usted, y por lo tanto su implementación de getItem()
siempre debería devolver una nueva instancia.
Entonces, para devolver un Fragmento existente, simplemente haga (asumiendo que está llamando desde ViewPager
):
Fragment f = (Fragment) getAdapter().instantiateItem(this, getCurrentItem());
He implementado algo similar a lo que tienes. Extendí la clase FragmentPagerAdapter
así:
public class ContactsFragmentPagerAdapter extends FragmentPagerAdapter {
ActionBar mActionBar;
private List<Fragment> mFragments;
public ContactsFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
mFragments = fragments;
}
@Override
public int getCount() {
return mFragments.size();
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
public void setActionBar(ActionBar bar) {
mActionBar = bar;
}
}
Observe que he agregado un argumento al constructor para pasar en la List
de objetos de Fragment
. De esta manera, el método getItem()
de esta clase puede devolver cualquier clase que extienda Fragment
o cualquiera de sus subclases y no solo una clase específica ArrayListFragment
como usted lo ha hecho.
En la Activity
donde he creado una instancia de mi subclase de FragmentPagerAdapter
, he pasado en la lista de objetos Fragment
:
Clasifique las instancias del FragmentPagerAdapter
public final class ContactManager extends Activity {
private ContactsFragmentPagerAdapter mAdapter;
private ViewPager mPager;
public ActionBar mActionBar;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.contact_manager);
List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, ContactsListFragment.class.getName()));
fragments.add(Fragment.instantiate(this, GroupsListFragment.class.getName()));
mAdapter = new ContactsFragmentPagerAdapter(this.getFragmentManager(), fragments);
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageScrollStateChanged(int arg0) {}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
@Override
public void onPageSelected(int arg0) {
mActionBar.getTabAt(arg0).select();
}
});
}
}
Al acceder a la variable "fragmentos", puede acceder a un Fragment
creado previamente para que pueda ejecutar los métodos de ese Fragment
.
No es necesario modificar el FragmentPagerAdapter, porque FragmentManager almacena en caché los fragmentos. Por lo que debe ser necesario encontrar dentro de ella. Utilice esta función para encontrar el fragmento por posición del adaptador de buscapersonas.
public Fragment findFragmentByPosition(int position) {
FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
return getSupportFragmentManager().findFragmentByTag(
"android:switcher:" + getViewPager().getId() + ":"
+ fragmentPagerAdapter.getItemId(position));
}
Código de ejemplo para v4 soporte api.
Si bien la solución de @ imiric es muy concisa, todavía me molesta que requiera conocimiento de la implementación de la clase. Mi solución consiste en agregar lo siguiente a su adaptador, que debería comportarse bien con un FragmentStatePagerAdager que posiblemente destruya fragmentos:
private SparseArray<WeakReference<Fragment>> mFragments = new SparseArray<>();
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment f = (Fragment) super.instantiateItem(container, position);
mFragments.put(position, new WeakReference<>(f)); // Remember what fragment was in position
return f;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
mFragments.remove(position);
}
public Fragment getFragment(int position) {
WeakReference<Fragment> ref = mFragments.get(position);
Fragment f = ref != null ? ref.get() : null;
if (f == null) {
Log.d(TAG, "fragment for " + position + " is null!");
}
return f;
}
public class MyPagerAdapter extends FragmentStatePagerAdapter {
final Context m_context;
final WeakReference<Fragment>[] m_fragments;
public DetailPagerAdapter(FragmentManager fm) {
super(fm);
m_context = ...
m_fragments = new WeakReference[enter size here];
}
@Override
public Fragment getItem(int position) {
final Fragment fragment = instantiate your fragment;
m_fragments[position] = new WeakReference<Fragment>(fragment);
return fragment;
}
@Override
public int getCount() {
return ...
}
public Fragment getFragment(final int position) {
return m_fragments[position] == null ? null :
m_fragments[position].get();
}
}