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 a FragmentStatePagerAdapter
.
Se você está lendo isso, provavelmente já sabe que FragmentPagerAdapter
/ FragmentStatePagerAdapter
deve ser criado Fragments
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 para Fragments
trabalhar com eles. Você não tem um id
ou tag
para estes criados Fragments
porque os FragmentPagerAdapter
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
chamando FragmentManager.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 a tag
estrutura que quebraria o seu código, deixando você incapaz de encontrar uma referência ao existente Fragments
.
Solução alternativa sem depender de internos tag
Aqui está um exemplo simples de como obter uma referência ao Fragments
retornado por FragmentPagerAdapter
que não dependa do tags
conjunto interno do Fragments
. A chave é substituir instantiateItem()
e salvar as referências lá em vez de em getItem()
.
public class SomeActivity extends Activity {
private FragmentA m1stFragment;
private FragmentB m2ndFragment;
// other code in your Activity...
private class CustomPagerAdapter extends FragmentPagerAdapter {
// other code in your custom FragmentPagerAdapter...
public CustomPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
// Do NOT try to save references to the Fragments in getItem(),
// because getItem() is not always called. If the Fragment
// was already created then it will be retrieved from the FragmentManger
// and not here (i.e. getItem() won't be called again).
switch (position) {
case 0:
return new FragmentA();
case 1:
return new FragmentB();
default:
// This should never happen. Always account for each position above
return null;
}
}
// Here we can finally safely save a reference to the created
// Fragment, no matter where it came from (either getItem() or
// FragmentManger). Simply save the returned Fragment from
// super.instantiateItem() into an appropriate reference depending
// on the ViewPager position.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// save the appropriate reference depending on position
switch (position) {
case 0:
m1stFragment = (FragmentA) createdFragment;
break;
case 1:
m2ndFragment = (FragmentB) createdFragment;
break;
}
return createdFragment;
}
}
public void someMethod() {
// do work on the referenced Fragments, but first check if they
// even exist yet, otherwise you'll get an NPE.
if (m1stFragment != null) {
// m1stFragment.doWork();
}
if (m2ndFragment != null) {
// m2ndFragment.doSomeWorkToo();
}
}
}
ou se você preferir trabalhar com em tags
vez de variáveis / referências de membros de classe, Fragments
você também pode pegar o tags
conjunto FragmentPagerAdapter
da mesma maneira: NOTA: isso não se aplica a, FragmentStatePagerAdapter
pois não é definido tags
ao criar seu Fragments
.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// get the tags set by FragmentPagerAdapter
switch (position) {
case 0:
String firstTag = createdFragment.getTag();
break;
case 1:
String secondTag = createdFragment.getTag();
break;
}
// ... save the tags somewhere so you can reference them later
return createdFragment;
}
Observe que este método NÃO depende da imitação do tag
conjunto interno FragmentPagerAdapter
e, em vez disso, usa APIs adequadas para recuperá-los. Desta forma, mesmo que as tag
alterações em versões futuras do, SupportLibrary
você ainda esteja seguro.
Não esqueça que dependendo do design do seu Activity
, o que Fragments
você está tentando trabalhar pode ou não existir, então você deve levar isso em consideração fazendo null
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 seu Fragments
porque você pode ter muitas delas e referências rígidas as manteriam desnecessariamente na memória. Em vez disso, salve as Fragment
referências em WeakReference
variáveis em vez de nas padrão. Como isso:
WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
// ...and access them like so
Fragment firstFragment = m1stFragment.get();
if (firstFragment != null) {
// reference hasn't been cleared yet; do work...
}