FragmentPagerAdapter getItem não é chamado

123

Não consigo reutilizar o fragmento no FragmentPagerAdapter. Usando o método destroyItem (), ele está excluindo o fragmento, mas ainda não chama getItem () novamente. Existem apenas 2-3 imagens, portanto, estou usando o FragmentPagerAdapter em vez do FragmentStatePagerAdapter.

public class ExamplePagerAdapter extends FragmentPagerAdapter {

    ArrayList < String > urls;
    int size = 0;
    public ExamplePagerAdapter(FragmentManager fm, ArrayList < String > res) {
        super(fm);
        urls = res;
        size = urls.size();
    }

    @Override
    public int getCount() {
        if (urls == null) {
            return 0;
        } else {
            return size;
        }

    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        FragmentManager manager = ((Fragment) object).getFragmentManager();
        FragmentTransaction trans = manager.beginTransaction();
        trans.remove((Fragment) object);
        trans.commit();
    }

    @Override
    public Fragment getItem(int position) {

        Fragment fragment = new FloorPlanFragment();
        Bundle b = new Bundle();
        b.putInt("p", position);
        b.putString("image", urls.get(position));
        Log.i("image", "" + urls.get(position));
        fragment.setArguments(b);
        return fragment;
    }
}

E em FragmentActivity,

pager.setAdapter(new ExamplePagerAdapter(getSupportFragmentManager(), res2)); 
Kanika
fonte
3
Existe uma razão específica para você substituir destroyItem()? Isso não é necessário.
CommonsWare
para inicializar novamente, use FragmentStatePagerAdapter também chamado quando você o substitui super.destroyItem (container, position, object);
faiziii

Respostas:

306

Resposta do KISS:

Uso simples FragmentStatePagerAdapter em vez de FragmentPagerAdapter .

Eu recebi a resposta .. Primeiro, pensei em excluir esta pergunta, pois estou cometendo um erro muito bobo, mas essa resposta ajudará alguém que está enfrentando o mesmo problema que Em vez de FragmentPagerAdapterusar FragmentStatePagerAdapter.

Como @BlackHatSamurai mencionado no comentário:

A razão pela qual isso funciona é porque FragmentStatePagerAdapterdestrói como fragmentos que não estão sendo usados. FragmentPagerAdapternão.

Kanika
fonte
Muito obrigado. Nossa resposta me ajudou muito.
Priya
1
Odeio ser outro 'eu também!' post, mas sim>. <Obrigado por não excluir a pergunta.
Paul Ruiz
34
O motivo disso funciona é porque o FragmentStatePagerAdapter destrói como fragmentos que não estão sendo usados. FragmentPagerAdapter não.
BlackHatSamurai
3
Apenas para referência futura para aqueles que podem encontrar isso enquanto procuram um problema específico que estão tendo; leia sobre FragmentPagerAdapter e FragmentStatePagerAdapter. Eles se comportam de maneira diferente por um motivo e seu uso específico pode exigir um sobre o outro.
Chris Stewart
2
@najibputhawala Eu usei o FragmentStatePagerAdapter, mas ainda enfrento o mesmo problema. getItem () não chamado
sam_k 17/06
168

O uso de um FragmentStatePagerAdapterproblema não corrigiu completamente o problema, que era um problema semelhante em que onCreateViewnão estava sendo chamado por fragmentos filhos no pager da exibição. Na verdade, estou aninhando meu FragmentPagerAdapterinterior de outro,Fragment portanto, ele FragmentManagerfoi compartilhado em todos eles e, assim, retendo instâncias dos fragmentos antigos. A correção foi alimentar uma instância do getChildFragmentManagerpara o construtor do FragmentPagerAdapterno meu fragmento de host. Algo como...

FragmentPagerAdapter adapter = new FragmentPagerAdapter(getChildFragmentManager());

O getChildFragmentManager()método é acessível por meio de um fragmento e isso funcionou para mim porque retorna um particular FragmentManagerpara esse fragmento especificamente para situações nas quais é necessário um fragmento de aninhamento. Espero que isso ajude alguém que possa estar tendo o mesmo problema que eu estava !!

  • No entanto, lembre-se de que o uso da getChildFragmentManager()sua versão mínima da API deve ser pelo menos 17 (4.2), portanto, isso pode gerar uma chave inglesa nas suas marchas. Obviamente, se você estiver usando fragmentos da biblioteca de suporte v4, deverá ficar bem.
Jraco11
fonte
25
Essa é a resposta correta. O problema é que os fragmentos aninhados em outros fragmentos devem usar getChildrenFragmentManager () em vez de getFragmentManager ().
shihpeng
Muito obrigado, demorei uma eternidade para encontrar esta resposta!
Shpongoloid
Eu concordo com @shihpeng. Essa deve ser a resposta correta.
Raymond Lukanta
Este foi um conserto para mim. Muito obrigado por enviar uma resposta
user3734429
Os documentos devem realmente chamar isso de explicação. É altamente realista que um ViewPager seja carregado dentro de um fragmento. Obrigado por postar esta resposta.
trabalhou
7

Sobrepor long getItemId (int position)

FragmentPagerAdapterarmazena em cache os fragmentos criados usando getItem. Eu estava enfrentando o mesmo problema - mesmo depois de ligar notifyDataSetChanged() getItemnão estava sendo chamado.

Este é realmente um recurso e não um bug. Você precisa substituir getItemIdpara poder reutilizar corretamente seus fragmentos. Como você está removendo fragmentos, suas posições estão mudando. Conforme mencionado nos documentos:

long getItemId (int position)

Retorne um identificador exclusivo para o item na posição especificada.

A implementação padrão retorna a posição especificada. As subclasses devem substituir esse método se as posições dos itens puderem mudar.

Basta fornecer um ID exclusivo para cada fragmento e pronto.

Usando um FragementStatePagerAdapterou retornando POSITION_NONEem int getItemPosition (Object object)está errado. Você não receberá nenhum cache.

vedante
fonte
Essa foi a resposta correta. Eu tive que fornecer IDs diferentes para os fragmentos em getItemIdAND ajustar getItemPositionpara retornar POSITION_NONEse o fragmento deveria ser removido. Eu tenho uma bandeira enum para isso. Depois disso getItemserá chamado.
Murat Karagöz 17/01
Obrigado @ MuratKaragöz pelos +50 :)
vedant 20/01
5

Fiz o que @kanika e @ Jraco11 haviam postado, mas ainda tinha o problema.

Então, depois de muitas alterações, encontrei uma que funcionou para mim e foi adicionada ao meu FragmentPagerAdapter o seguinte código:

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

De acordo com o que li, getItemPosition é usado para notificar o ViewPager sobre a atualização ou não de um item e para evitar atualizações se os itens nas posições visíveis não forem alterados.

Jorge Casariego
fonte
2

Existem dois cenários diferentes: 1.) Você tem o mesmo layout para cada pager: nesse caso, será melhor se você estender seu adaptador personalizado pelo PagerAdapter e retornar um único layout.

2.) Você tem um layout diferente para cada pager: nesse caso, será melhor se você estender seu adaptador personalizado pelo FragmentStatePagerAdapter e retornar fragmentos diferentes para cada pager.

Maddy
fonte
2

O método getItem()é usado apenas para criar novos itens. Uma vez criados, esse método não será chamado. Se você precisar obter o item que é moeda em uso pelo adaptador, use este método:

pagerAdapter.instantiateItem(viewPager, TAB_POS)
B-GangsteR
fonte
0

Descobri que a configuração de um ouvinte no layout da guia impediu que isso fosse chamado, provavelmente porque eles só têm espaço para um ouvinte, em tabLayout.setOnTabSelectedListenervez de um conjunto de ouvintes.

Oliver Dixon
fonte