Tenho problemas para fazer meus fragmentos se comunicarem uns com os outros por meio do Activity
, que está usando o FragmentPagerAdapter
, como uma classe auxiliar que implementa o gerenciamento de guias e todos os detalhes de conexão ViewPager
com um associado TabHost
. Implementei FragmentPagerAdapter
da mesma forma que é fornecido pelo projeto de amostra do Android Support4Demos .
A principal questão é como posso obter um fragmento específico de FragmentManager
quando não tenho ID ou Tag? FragmentPagerAdapter
está criando os fragmentos e gerando automaticamente o Id e as tags.
android
android-fragments
fragmentpageradapter
Ismar Slomic
fonte
fonte
Respostas:
Resumo do problema
Nota: nesta resposta vou fazer referência
FragmentPagerAdapter
e seu código-fonte. Mas a solução geral também deve ser aplicada aFragmentStatePagerAdapter
.Se você está lendo isso, provavelmente já sabe que
FragmentPagerAdapter
/FragmentStatePagerAdapter
deve ser criadoFragments
para vocêViewPager
, mas após a recriação da atividade (seja a partir de uma rotação do dispositivo ou do sistema matando seu aplicativo para recuperar a memória),Fragments
não serão criados novamente, mas sim seus instâncias recuperadas doFragmentManager
. Agora diga que vocêActivity
precisa de uma referência paraFragments
trabalhar com eles. Você não tem umid
outag
para estes criadosFragments
porque osFragmentPagerAdapter
define internamente . Então o problema é como obter uma referência a eles sem essa informação ...Problema com as soluções atuais: depender de código interno
Muitas das soluções que eu vi sobre este e outras questões semelhantes confiar em obter uma referência ao existente
Fragment
chamandoFragmentManager.findFragmentByTag()
e imitando o tag criado internamente:"android:switcher:" + viewId + ":" + id
. O problema com isso é que você está contando com o código-fonte interno, que como todos sabemos não é garantido que permaneça o mesmo para sempre. Os engenheiros do Android no Google poderiam facilmente decidir mudar atag
estrutura que quebraria o seu código, deixando você incapaz de encontrar uma referência ao existenteFragments
.Solução alternativa sem depender de internos
tag
Aqui está um exemplo simples de como obter uma referência ao
Fragments
retornado porFragmentPagerAdapter
que não dependa dotags
conjunto interno doFragments
. A chave é substituirinstantiateItem()
e salvar as referências lá em vez de emgetItem()
.ou se você preferir trabalhar com em
tags
vez de variáveis / referências de membros de classe,Fragments
você também pode pegar otags
conjuntoFragmentPagerAdapter
da mesma maneira: NOTA: isso não se aplica a,FragmentStatePagerAdapter
pois não é definidotags
ao criar seuFragments
.Observe que este método NÃO depende da imitação do
tag
conjunto internoFragmentPagerAdapter
e, em vez disso, usa APIs adequadas para recuperá-los. Desta forma, mesmo que astag
alterações em versões futuras do,SupportLibrary
você ainda esteja seguro.Não esqueça que dependendo do design do seu
Activity
, o queFragments
você está tentando trabalhar pode ou não existir, então você deve levar isso em consideração fazendonull
verificações antes de usar suas referências.Além disso, se em vez disso você estiver trabalhando com o
FragmentStatePagerAdapter
, então não deseja manter referências rígidas para o seuFragments
porque você pode ter muitas delas e referências rígidas as manteriam desnecessariamente na memória. Em vez disso, salve asFragment
referências emWeakReference
variáveis em vez de nas padrão. Como isso:fonte
instantiateItem
. a maneira correta de fazer isso é chamarinstantiateItem
noonCreate
método de sua atividade cercado porstartUpdate
efinishUpdate
. Veja minha resposta para detalhesEu encontrei a resposta para minha pergunta com base na seguinte postagem: reutilizando fragmentos em um fragmentpageradapter
Poucas coisas que aprendi:
getItem(int position)
noFragmentPagerAdapter
nome enganoso do que esse método realmente faz. Ele cria novos fragmentos, não retornando os existentes. Nesse sentido, o método deve ser renomeado para algo comocreateItem(int position)
no Android SDK. Portanto, este método não nos ajuda a obter fragmentos.FragmentPagerAdapter
e, portanto, o que significa que você não tem nenhuma referência aos fragmentos ou suas tags. Se você tiver uma tag de fragmento, pode facilmente recuperar a referência a elaFragmentManager
chamandofindFragmentByTag()
. Precisamos encontrar uma maneira de descobrir a tag de um fragmento em determinada posição da página.Solução
Adicione o seguinte método auxiliar em sua classe para recuperar a tag do fragmento e enviá-la ao
findFragmentByTag()
método.NOTA! Este é um método idêntico
FragmentPagerAdapter
ao usado ao criar novos fragmentos. Veja este link http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/android/support/v2/app/FragmentPagerAdapter.java#104fonte
onAttach()
?você não precisa substituir
instantiateItem
nem confiar na compatibilidade com omakeFragmentName
método interno criando manualmente tags de fragmento.instantiateItem
é um método público , então você pode e realmente deve chamá-lo noonCreate
método de sua atividade rodeado de chamadas parastartUpdate
efinishUpdate
métodos descritos emPagerAdapter
javadoc :Você pode então, pelo caminho acima, armazenar referências a instâncias de seus fragmentos em vars locais, se necessário. Consultar exemplo:
instantiateItem
tentará primeiro obter referências a instâncias de fragmento existentes deFragmentManager
. Somente se eles ainda não existirem, ele criará novos usando ogetItem
método de seu adaptador e "armazenará" noFragmentManager
para qualquer uso futuro.É importante observar que, mesmo que você não precise obter referências para seus fragmentos, você ainda deve chamar
instantiateItem
todas as suas guias circundadas porstartUpdate
/finishUpdate
em seuonCreate
método desta forma:Se você não fizer isso, então você está arriscando que suas instâncias de fragmentos nunca será comprometida com
FragmentManager
: quando a sua atividade se torna planoinstantiateItem
será chamado automaticamente para obter os seus fragmentos, masstartUpdate
/finishUpdate
pode não (dependendo de detalhes de implementação) eo que eles basicamente fazer é começar / confirmar aFragmentTransaction
.Isso pode resultar em referências às instâncias de fragmento criadas sendo perdidas muito rapidamente (por exemplo, quando você gira sua tela) e recriadas com muito mais frequência do que o necessário. Dependendo de quão "pesados" seus fragmentos são, isso pode ter consequências de desempenho não desprezíveis.
Além disso, em tais casos, as instâncias de fragmentos armazenados em vars locais podemtornam-se obsoletos: se a plataforma Android tentar obtê-los
FragmentManager
por algum motivo, ele falhará e, portanto, criará e usará novos, enquanto seus vars ainda farão referência aos antigos.fonte
FragmentManager
não pode simplesmente matar aleatoriamente ( destruir é a palavra certa aqui) seuFragment
(pense no que aconteceria se ele decidisse matar umFragment
que está sendo exibido atualmente;)). Geralmente o ciclo de vida de aFragment
está vinculado ao seuActivity
(consulte github.com/xxv/android-lifecycle para obter detalhes) -> aFragment
só pode ser destruído se tiverActivity
sido destruído. Nesse caso, quando um usuário navegar de volta para o dado,Activity
eleonCreate
será chamado novamente e uma nova instância deFragment
será criada.A forma como eu fiz isso é definir uma Hashtable de WeakReferences da seguinte maneira:
Então, escrevi o método getItem () assim:
Então você pode escrever um método:
Isso parece funcionar bem e acho um pouco menos hacky do que o
truque, pois não depende de como o FragmentPagerAdapter é implementado. Claro, se o fragmento foi liberado pelo FragmentPagerAdapter ou se ainda não foi criado, getFragment retornará null.
Se alguém encontrar algo errado com essa abordagem, comentários são mais que bem-vindos.
fonte
int fragmentId
deve ser renomeado paraint position
Eu criei este método que está funcionando para mim obter uma referência para o fragmento atual.
fonte
a solução sugerida por @ personne3000 é boa, mas tem um problema: quando a atividade vai para o fundo e é interrompida pelo sistema (para obter um pouco de memória livre) e depois restaurada, o
fragmentReferences
estará vazio, porquegetItem
não estaria chamado.A classe abaixo lida com essa situação:
fonte
O principal obstáculo para obter uma alça para os fragmentos é que você não pode confiar em getItem (). Após uma mudança de orientação, as referências aos fragmentos serão nulas e getItem () não será chamado novamente.
Aqui está uma abordagem que não depende da implementação de FragmentPagerAdapter para obter a tag. Substitua instantiateItem () que retornará o fragmento criado a partir de getItem () ou encontrado no gerenciador de fragmentos.
fonte
Veja esta postagem sobre como retornar fragmentos do FragmentPagerAdapter. Depende de você saber o índice do seu fragmento - mas isso seria definido em getItem () (apenas na instanciação)
fonte
Consegui resolver esse problema usando ids em vez de tags. (Estou usando o FragmentStatePagerAdapter que usa meus fragmentos personalizados nos quais substituí o método onAttach, onde você salva o id em algum lugar:
E então você apenas acessa o fragmento facilmente dentro da atividade:
fonte
Não sei se esta é a melhor abordagem, mas nada mais funcionou para mim. Todas as outras opções, incluindo getActiveFragment, retornaram null ou fizeram o aplicativo travar.
Percebi que na rotação da tela o fragmento estava sendo anexado, então usei para enviar o fragmento de volta para a atividade.
No fragmento:
Então, na atividade:
E finalmente na atividade onCreate ():
Essa abordagem anexa o fragmento visível real à atividade sem criar um novo.
fonte
Não tenho certeza se meu método era o correto ou a melhor maneira de fazer isso, já que sou relativamente iniciante em Java / Android, mas funcionou (tenho certeza de que viola os princípios de orientação a objetos, mas nenhuma outra solução funcionou para meu caso de uso).
Eu tinha uma atividade de hospedagem que estava usando um ViewPager com um FragmentStatePagerAdapter. Para obter referências aos fragmentos criados por FragmentStatePagerAdapter, criei uma interface de retorno de chamada dentro da classe de fragmento:
Na atividade de hospedagem, implementei a interface e criei um LinkedHasSet para rastrear os fragmentos:
Na classe ViewPagerFragment, adicionei os fragmentos à lista em onAttach e os removi em onDetach:
Dentro da atividade de hospedagem, você agora poderá usar mFragments para iterar através dos fragmentos que existem atualmente no FragmentStatePagerAdapter.
fonte
Esta classe faz o truque sem depender de tags internas. Aviso: os fragmentos devem ser acessados usando o método getFragment e não getItem.
fonte
Basta tentar este código,
fonte