I'm changing the navigation of an app to work in as follows: the app will contain a single activity which initially shows a ViewPager
with three views (fragments), and in one of the views there is a button which replaces these fragments with two other fragments.
I found out in this answer that I cannot use FragmentPagerAdapter
because it never destroys a fragment after having displayed it for the first time; as I wish to swap the fragments, I will have to use FragmentStatePagerAdapter
while being sure to always return a new fragment instance in the method getItem(int position)
. However, for the ViewPager
to effectively update the views after changing the adapter bound to it (actually I don't change the adapter, only the data associated to it, which I use to instantiate the fragments), I must override the method getItemPosition(Object object)
for it to return POSITION_NONE
and call notifyDataSetChanged()
in the adapter. However, the views are not being updated after that process (and that is exactly my problem).
My code follows:
ConfiguracoesDeItemDoViewPager.java (contains the data necessary for the adapter to instantiate a new fragment):
public static class ConfiguracoesDeItemDoViewPager {
private String nomeDaAba;
private Class<? extends FragmentoBase> classeDoFragmento;
private Bundle argumentosDoFragmento;
public ConfiguracoesDeItemDoViewPager(String nomeDaAba, Class<? extends FragmentoBase> classeDoFragmento, Bundle argumentosDoFragmento) {
this.nomeDaAba = nomeDaAba;
this.classeDoFragmento = classeDoFragmento;
this.argumentosDoFragmento = argumentosDoFragmento;
}
public String getNomeDaAba() {
return nomeDaAba;
}
public void setNomeDaAba(String nomeDaAba) {
this.nomeDaAba = nomeDaAba;
}
public Class<? extends FragmentoBase> getClasseDoFragmento() {
return classeDoFragmento;
}
public void setClasseDoFragmento(
Class<? extends FragmentoBase> classeDoFragmento) {
this.classeDoFragmento = classeDoFragmento;
}
public Bundle getArgumentosDoFragmento() {
return argumentosDoFragmento;
}
public void setArgumentosDoFragmento(Bundle argumentosDoFragmento) {
this.argumentosDoFragmento = argumentosDoFragmento;
}
}
Constantes.java (provides the data to configure a ViewPager with a set of fragments):
public class Constantes {
public static final ConfiguracoesDeItemDoViewPager [] CONFIGURACOES_DO_VIEWPAGER_1;
public static final ConfiguracoesDeItemDoViewPager [] CONFIGURACOES_DO_VIEWPAGER_2;
// Bloco de inicialização de valores estáticos
static {
CONFIGURACOES_DO_VIEWPAGER_1 = new DadosDeItemDoViewPager[3];
CONFIGURACOES_DO_VIEWPAGER_1[0] = new DadosDeItemDoViewPager("Aba 1", FragmentoA.class, null);
CONFIGURACOES_DO_VIEWPAGER_1[1] = new DadosDeItemDoViewPager("Aba 2", FragmentoB.class, null);
CONFIGURACOES_DO_VIEWPAGER_1[2] = new DadosDeItemDoViewPager("Aba 3", FragmentoC.class, null);
CONFIGURACOES_DO_VIEWPAGER_2 = new DadosDeItemDoViewPager[2];
CONFIGURACOES_DO_VIEWPAGER_2[0] = new DadosDeItemDoViewPager("Aba 1", FragmentoD.class, null);
CONFIGURACOES_DO_VIEWPAGER_2[1] = new DadosDeItemDoViewPager("Aba 2", FragmentoE.class, null);
}
...
}
AtividadePrincipal.java (the only activity in the app, having the inner class for a FragmentStatePagerAdapter):
public class AtividadePrincipal extends ActionBarActivity {
private ViewPager mViewPager;
private TabsPagerAdapter mTabsPagerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTabsPagerAdapter = new TabsPagerAdapter(getSupportFragmentManager(), Constantes.CONFIGURACOES_DO_VIEWPAGER_1);
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mTabsPagerAdapter);
}
public void exibirViewPager2() {
((TabsPagerAdapter)mViewPager.getAdapter()).setConfiguracoesParaInicializarViewPager(Constantes.CONFIGURACOES_DO_VIEWPAGER_2);
}
public class TabsPagerAdapter extends FragmentStatePagerAdapter {
private FragmentManager mFragmentManager;
private ConfiguracoesDeItemDoViewPager [] mConfiguracoesDeItensDoViewPager;
public TabsPagerAdapter(FragmentManager fm, ConfiguracoesDeItensDoViewPager [] configuracoesDeItensDoViewPager) {
super(fm);
this.mFragmentManager = fm;
this.mConfiguracoesDeItensDoViewPager = configuracoesDeItensDoViewPager;
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
@Override
public Fragment getItem(int indice) {
Fragment fragmento = null;
try {
fragmento = mConfiguracoesDeItensDoViewPager[indice].getClasseDoFragmento().newInstance();
if (mConfiguracoesDeItensDoViewPager[indice].getArgumentosDoFragmento() != null) {
fragmento.setArguments(mConfiguracoesDeItensDoViewPager[indice].getArgumentosDoFragmento());
}
} catch (IllegalAccessException e) {
Log.e(Logs.gerarTagParaFiltragemNoLogCat(AtividadePrincipal.this, this), "Exceção inesperada!", e);
} catch (InstantiationException e) {
Log.e(Logs.gerarTagParaFiltragemNoLogCat(AtividadePrincipal.this, this), "Exceção inesperada!", e);
}
return fragmento;
}
@Override
public int getCount() {
return mConfiguracoesDeItensDoViewPager.length;
}
@Override
public CharSequence getPageTitle(int posicao) {
return mConfiguracoesDeItensDoViewPager[posicao].getNomeDaAba();
}
public void setConfiguracoesParaInicializarViewPager(ConfiguracoesDeItemDoViewPager [] configuracoes) {
// Remove um fragmento extra contido dentro do FragmentoB, que se for
// deixado no FragmentManager causa erro de id duplicado
FragmentTransaction ft = mFragmentManager.beginTransaction();
Fragment fragmento = mFragmentManager.findFragmentById(R.id.mapa);
if (fragmento != null && fragmento instanceof SupportMapFragment) {
ft.remove(fragmento);
}
ft.commit();
this.mConfiguracoesDeItensDoViewPager = configuracoes;
notifyDataSetChanged();
}
}
}
Just to complete the explanation: when the use clicks a button in one of the fragments, the
method AtividadePrincipal.exibirViewPager2()
is called. It is supposed to update the ViewPager
views/fragments, which doesn't happen.