1

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.

Community
  • 1
  • 1
João Victor
  • 91
  • 1
  • 6

1 Answers1

1

I have tried this and it recreates/reloads the fragment (onCreate is called). In your AtividadePrincipal.exibirViewPager2() method add this line.

    this.mViewPager.setAdapter(mTabsPagerAdapter);
k1slay
  • 1,068
  • 1
  • 10
  • 18
  • Actually calling this line a second time is not necessary since the adapter reference `mTabsPagerAdapter` is kept unchanged. But I found out what the error was -- a typo in the original code that made `CONFIGURACOES_DO_VIEWPAGER_2` point to `CONFIGURACOES_DO_VIEWPAGER_1` so the views would appear to be unchanged. Since you mentioned the fragment is recreated, your answer helped me to figure out the error and I am willing to accept it for your effort. Please mention what the actual fix was in the answer if you don't mind. Thanks! – João Victor Jun 05 '14 at 13:35
  • Not really a fix, but I just found that setting the adapter again for the viewpager reloads the whole viewpager, thus if some data has changed it will load the viewpager with the new data – k1slay Jun 05 '14 at 13:41
  • As you certainly know, that's what `notifyDataSetChanged()` is for. :) – João Victor Jun 05 '14 at 13:43
  • yes but I have found that `notifyDataSetChanged()` doesn't always work as expected, I tried updating a few listviews in my apps but it refused to change, So I had to come up with my own custom methods. I thought you had a similar issue. – k1slay Jun 05 '14 at 13:49