O fragmento no ViewPager usando FragmentPagerAdapter fica em branco na segunda vez que é visualizado

98

Eu tenho uma interface de fragmento com guias na parte inferior que abrem diferentes fragmentos na visualização principal.

Eu tenho um fragmento específico que é uma lista de itens. Se o usuário selecionar um dos itens nesta lista, outro fragmento é aberto, contendo um visualizador que rola horizontalmente entre todos os itens da lista do fragmento anterior. Isso funciona muito bem.

O viewpager usa um FragmentPagerAdapter para exibir os itens.

O problema surge quando o usuário seleciona um item da lista, visualiza-o e, em seguida, clica no botão na barra de guias para voltar à lista e seleciona outro item. Na segunda vez que um item é selecionado, uma tela em branco aparece em vez do viewpager. Não recebo erros no meu LogCat quando isso acontece.

Por que o viewpager está aparecendo apenas na primeira vez?

FragmentPagerAdapter:

public class ViewPagerAdapter extends FragmentPagerAdapter {
    Cursor mCursor;

    public ViewPagerAdapter(FragmentManager fm, Cursor c) {
        super(fm);
        mCursor = c;
    }

    public void changeCursor(Cursor c) {
        mCursor = c;
        this.notifyDataSetChanged();
    }

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

    @Override
    public Fragment getItem(int position) {
        mCursor.moveToPosition(position);
        return TeamCardFragment.newInstance(mCursor, position);
    }
}

PagerFragment:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);

    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);

    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();

    return mView;
}

private class setAdapterTask extends AsyncTask<Void, Void, Void> {
    protected Void doInBackground(Void... params) {
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        mViewPager.setAdapter(mAdapter);
        mViewPager.setCurrentItem(mCursorPosition);
    }
}
uivo
fonte

Respostas:

221

Eu tive o mesmo problema. Alterar a classe pai do meu PageAdapter de android.support.v4.app.FragmentPagerAdapterpara android.support.v4.app.FragmentStatePagerAdapterresolver meu ViewPagerproblema de exibição na "segunda vez"!

Yann
fonte
2
Sem brincadeiras? Não tenho mais esse código, senão o testaria. Talvez esta resposta ajude outra pessoa.
Howettl
10
Que homem! Fiquei procurando essa solução por dias! Muito obrigado cara, funciona como um encanto. Mas o desenvolvedor em mim está perguntando que impacto essa mudança causa? Quero dizer, por que não funcionou antes e por que em StatePagerAdapter
Anand Sainath
1
você também precisa @Override public int getItemPosition (Object object) {return POSITION_NONE; }
Helin Wang
1
Funcionou para mim também. Aqui está um link. Parece salvar o estado do fragmento, o que faz toda a diferença. developer.android.com/reference/android/support/v4/app/…
Tjaart
1
É uma coincidência que funcione, a resposta certa é @Daniel F's. De qualquer forma, para conveniência dos comentadores aqui, a diferença entre FragmentPagerAdaptere FragmentStatePagerAdapterestá no primeiro sendo mais adequado para poucas páginas, ele retém todos os fragmentos na memória, portanto, tendo melhores desempenhos na troca de página, enquanto o último é mais adequado para muitos páginas, ele destrói fragmentos, mantendo apenas seu estado, é mais eficiente em termos de memória, mas um pouco mais lento na troca de página.
Cristina De Rito de
87

Consegui resolver isso substituindo getFragmentManager()por getChildFragmentManager()no fragmento pai. Este fragmento pai instanciava um android.support.v4.app.FragmentPagerAdapter para conter fragmentos pagináveis ​​(deslizáveis), o que requer um gerenciador de fragmentos no construtor. Para esse construtor, passei o valor de retorno de getChildFragmentManager().

O link do hackbod era a chave ( https://developer.android.com/about/versions/android-4.2.html#NestedFragments ), que foi encontrado nesta postagem Fragments within Fragments

Para aninhar um fragmento, basta chamar getChildFragmentManager()o fragmento ao qual deseja adicionar um fragmento. Isso retorna um FragmentManager que você pode usar como normalmente faz na atividade de nível superior para criar transações de fragmento.

Daniel F
fonte
Obrigado ... eu estava tendo um problema semelhante ao tentar reinstanciar uma exibição de guias deslizantes após onresume () que continha um fragmentpageradapter ... o tutorial que usei era de 2016 e ainda precisava alterá-lo para fragmentstatepageradapter para obtê-lo trabalhos. gostaria de saber por quê.
Nerdy Bunz de
essa resposta economizou muito do meu tempo. Porque apenas usar FragmentStatePagerAdapternão resolve a questão aqui formulada. junto com o FragmentStatePagerAdapterfragmento pai YourAdapter adapter = new YourAdapter (getChildFragmentManager()); deve ser adicionado
MMK
17

para mim, tive que chamar isso no meu viewpager:

myViewPager.setSaveFromParentEnabled(false);

Tive o problema em que o viewpager não estava atualizando e tudo o que vi foi uma tela branca onde os fragmentos deveriam estar. Eu estava passando getChildFragmentManager, mas não ajudou.

j2emanue
fonte
1
Por que diabos isso funcionou? Isso corrigiu meu problema, mas não tenho ideia do porquê.
ClayHerendeen
Eu removi do meu código agora. O gerenciador de fragmentos estava causando o problema. Tente alternar entre getchildfragmentmanager e getfragmentmanager
j2emanue 01 de
Eu já tentei isso. Aninhei Guias, cada uma com ViewPagers que desativaram o deslizamento. Eu sei que este é um projeto ruim, mas os desejos dos clientes não os meus. Estou usando um childFragmentManager para a barra de guias de nível superior. Alternar para tabbar / viewpager de nível inferior não parece resolver o problema. Suponho que vou ficar com setSaveFromParentEnabled (false) por enquanto, já que está funcionando.
ClayHerendeen 01 de
Você está usando a biblioteca de suporte mais recente
j2emanue 01 de
2
Eu estava enfrentando o mesmo problema nos últimos 2 dias .. Sua solução funcionou para mim. obrigado !
brijexecon
11

No meu caso muito particular, onde eu estava usando um CoordinatorLayout com um AppBarLayout e o ViewPager, o que resolveu para mim foi remover o android: fitSystemWindows = "true" de minhas propriedades xml AppBarLayout .

Não me pergunte por quê. Eu sei que parece um pouco ridículo e como se não devesse ter correlação, mas era essa única linha a única coisa que estava causando problemas, pois eu já estava usando getChildFragmentManager () no meu adaptador. Passei um dia inteiro depurando meu código apenas para encontrar isso, então espero que poupe mais alguém algum tempo.

emirua
fonte
3
Oh cara ... Eu quase ia me render com esse problema. Você fez meu maldito dia! Nossa Google, WTF está errado com o AppBarLayout? Eu olhei quase cem páginas e passei muitas horas depurando tentando resolver esse problema sem sorte. Estou muito grato por finalmente ter resolvido o problema com seu comentário. Muito obrigado! PS: Eu estava tão desesperado que até criei um problema no AOSP: code.google.com/p/android/issues/… XD
Guillem Roca
Obrigado pela dica. Pelo menos nos ajudou a resolver o problema. Agora estamos tentando descobrir uma opção para torná-lo em tela inteira
Paresh Mayani
Você é um salva-vidas! Eu não sabia por que estava tendo esse problema e ainda não sabia por que funcionava!
nandu
10

Eu tive o mesmo problema pelo qual mudei o adaptador de FragmentPagerAdapterpara FragmentStatePagerAdaptere getFragmentManager()no fragmento pai paragetChildFragmentManager()

A razão por trás disso é FragmentStatePagerAdapterútil no armazenamento de um grande número de páginas e a memória associada a cada página visitada é menor, pois mantém apenas o estado salvo do fragmento enquanto a página não está visível. Isso reduz a sobrecarga ao alternar entre os fragmentos.

Yashaswi NP
fonte
4

Tente colocar setOffscreenPageLimit (int limit)em pai ViewPager.

mViewPager.setOffscreenPageLimit(totalPages-1);

Isso funcionou para mim como um charme.

No meu caso, eu tinha um fragmento dentro TabLayoutcomViewPager.

E outro ViewPagerdentro desse fragmento. Na primeira vez, tudo está funcionando bem, mas quando mudo a guia e volto, parte do meu fragmento fica em branco.

Rumit Patel
fonte
1
Boa resposta. Isso me ajudou.
Thirumalvalavan
2

Isso ajudaria você.

    viewPager.setOffscreenPageLimit(position);
Pardeep Singh
fonte
1

Contornamos isso reimplementando os itens do pager de visualização como visualizações padrão em vez de fragmentos e alterando o adaptador de acordo.

uivo
fonte
você pode tentar remover a função isViewFromObject (View view, Object object)
Mina Samy,
Deve haver uma maneira melhor ...: / embora quanto mais eu fujo no Android, menos maduro percebo que ele é.
StackOverflowed
1
Fragmentos aninhados não são suportados , portanto, a reimplementação com a visualização padrão parece ser o melhor caminho a seguir.
Sylphe
Estou lutando com um problema semelhante. Tentei usar PagerAdapter em vez de FragmentAdapter, mas ainda encontro o mesmo problema. Por favor, me ajude !
Gaurav Arora
Se você quiser usar fragmentos aninhados, pode usar o adaptador que forneci nesta resposta: stackoverflow.com/questions/7700226/…
Slickelito
1

Eu estava tendo esse mesmo problema no Xamarin Android com uma tela em branco na segunda vez .. Definir o seguinte corrigiu para mim.

viewPager.SaveFromParentEnabled = false;
Gerard
fonte
0

Você também pode inicializar o adaptador para os casos em que ocorrer esse erro quando seu aplicativo for minimizado e chamado posteriormente.

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);
    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);
    initViewPagerAdapter();
    return mView;
}
private void initViewPagerAdapter(){
    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();
}

@Override
public void onResume(){
    super.onResume();
    initViewPagerAdapter();
}
Patrick
fonte
0

Tive a mesma coisa, na segunda vez que chamo o Adaptador Pager, a visão filha retorna um NullPointerException. E mudar o adaptador em FragmentStatePagerAdapter resolve meu problema também.

Arka-57
fonte
0

Mude FragmentPagerAdapterpara FragmentStatePagerAdapter uso em getChildFragmentManager()vez degetFragmentManager()

getChildFragmentManager()- porque de acordo com a documentação, ele retornará um FragmentManager privado para colocar e gerenciar Fragments dentro deste Fragment. Enquanto isso getFragmentManager(), retornará o FragmentManager para interagir com fragmentos associados a esta atividade

Mostafa Anter
fonte
0

classe ViewPagerAdapter extends FragmentStatePagerAdapter este trabalho para mim, tente isto

Abdul Basit Abbasi
fonte