FragmentManager
é
a classe responsável por executar ações nos fragmentos do app, como
adicionar, remover ou substituir, e adicioná-los à pilha de retorno.
Talvez você nunca interaja com o FragmentManager
diretamente se estiver usando
a biblioteca Jetpack Navigation, já que ela trabalha com
FragmentManager
em seu nome. Sendo assim, qualquer app que use fragmentos está
usando o FragmentManager
em algum nível, então é importante entender o que
ele é e como funciona.
Este tópico aborda como acessar o FragmentManager
, o papel do
FragmentManager
em relação às suas atividades e aos seus fragmentos, como gerenciar
a pilha de retorno com FragmentManager
e como fornecer dados e dependências
aos seus fragmentos.
Acessar o FragmentManager
Como acessar em uma atividade
Cada FragmentActivity
e subclasse, como a
AppCompatActivity
,
tem acesso ao FragmentManager
pelo
método
getSupportFragmentManager()
.
Como acessar em um fragmento
Os fragmentos também são capazes de hospedar um ou mais fragmentos filhos. Dentro de
um fragmento, é possível conseguir uma referência ao FragmentManager
que gerencia
os filhos do fragmento pelo
getChildFragmentManager()
.
Se você precisar acessar o host FragmentManager
, use
getParentFragmentManager()
.
Veja alguns exemplos para conhecer as relações entre
os fragmentos, os hosts deles e as instâncias do FragmentManager
associadas a
cada um.

A Figura 1 mostra dois exemplos, cada um deles com um único host de atividade. A
atividade do host em ambos os exemplos exibe uma navegação de nível superior para
o usuário como uma
BottomNavigationView
responsável por trocar o fragmento de host com diferentes telas
no app, com cada uma implementada como um fragmento separado.
O fragmento de host no Exemplo 1 hospeda dois fragmentos filhos que compõem uma tela de visualização dividida. O fragmento de host no Exemplo 2 hospeda um único fragmento filho que compõe o fragmento de exibição de uma visualização deslizável.
Considerando essa configuração, é possível pensar em cada host como tendo um FragmentManager
associado a ele e que gerencia os fragmentos filhos. Isso é ilustrado na
Figura 2, assim como os mapeamentos de propriedades entre supportFragmentManager
,
parentFragmentManager
e childFragmentManager
.

FragmentManager
associado que gerencia os
fragmentos filhos.A propriedade FragmentManager
adequada para referência depende de onde está
o local de chamadas na hierarquia de fragmentos e de qual gerenciador de fragmentos
você está tentando usar para o acesso.
Quando você tiver uma referência ao FragmentManager
, poderá usá-la para
manipular os fragmentos exibidos ao usuário.
Fragmentos filhos
De modo geral, o app precisa consistir em um número pequeno ou único
de atividades no projeto do aplicativo, com cada uma representando
um grupo de telas relacionadas. A atividade pode fornecer um ponto para posicionar
a navegação de nível superior e um local para o escopo de ViewModels
e outro estado de visualização
entre fragmentos. Cada destino individual no app precisa ser
representado por um fragmento.
Se você quiser exibir vários fragmentos de uma só vez, como em uma visualização dividida ou em um painel, use fragmentos filhos gerenciados pelo fragmento de destino e pelo gerenciador de fragmentos filhos.
Outros casos de uso para fragmentos filhos podem incluir os seguintes:
- Deslizes de tela,
com um
ViewPager2
em um fragmento pai para gerenciar uma série de visualizações do fragmento filho. - Subnavegação em um conjunto de telas relacionadas.
- O Jetpack Navigation usa fragmentos filhos como destinos individuais. Uma
atividade hospeda um único
NavHostFragment
pai e preenche o espaço com diferentes fragmentos de destino filhos à medida que os usuários navegam pelo app.
Como usar o FragmentManager
O FragmentManager
gerencia a pilha de retorno de fragmentos. No ambiente de execução, o
FragmentManager
pode executar operações de pilha de retorno, como a adição ou remoção de
fragmentos em resposta a interações do usuário. Cada conjunto de mudanças é
combinado como uma única unidade chamada
FragmentTransaction
.
Para ver uma discussão mais aprofundada sobre transações de fragmentos, consulte o
guia de transações de fragmentos.
Quando o usuário pressiona o botão Voltar no dispositivo ou quando você chama
FragmentManager.popBackStack()
,
a transação de fragmento na camada superior é removida da pilha. Em outras
palavras, a transação é revertida. Se não houver mais transações de
fragmentos na pilha e se você não estiver usando fragmentos filhos, o evento de
retorno surgirá na atividade. Se você estiver usando fragmentos filhos, consulte as
considerações especiais para fragmentos filhos e irmãos.
Quando você chama
addToBackStack()
em uma transação, ela pode incluir qualquer número de
operações, como a adição de vários fragmentos, substituição de fragmentos em vários
contêineres e assim por diante. Quando a pilha de retorno é encerrada, todas essas
operações são revertidas para uma única ação atômica. Se você tiver confirmado
outras transações antes da chamada de popBackStack()
e se
não tiver usado addToBackStack()
na transação, essas operações
não serão revertidas. Portanto, em uma única FragmentTransaction
, evite
intercalar transações que afetam a pilha de retorno com as que não fazem isso.
Realizar uma transação
Para exibir um fragmento em um contêiner de layout, use o FragmentManager
para criar uma FragmentTransaction
. Dentro da transação, é possível
realizar uma operação
add()
ou replace()
no contêiner.
Por exemplo, uma FragmentTransaction
simples pode ter esta aparência:
Kotlin
supportFragmentManager.commit { replace<ExampleFragment>(R.id.fragment_container) setReorderingAllowed(true) addToBackStack("name") // name can be null }
Java
FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.fragment_container, ExampleFragment.class, null) .setReorderingAllowed(true) .addToBackStack("name") // name can be null .commit();
Nesse exemplo, ExampleFragment
substitui o fragmento, se houver, que está
no contêiner de layout identificado pelo
ID R.id.fragment_container
. Fornecer a classe do fragmento ao
método replace()
permite que o FragmentManager
processe a instanciação usando
FragmentFactory
.
Para mais informações, consulte Como fornecer dependências.
setReorderingAllowed(true)
otimiza as mudanças de estado dos fragmentos envolvidos na transação
para que as animações e transições funcionem corretamente. Para ver mais informações sobre
como navegar com animações e transições, consulte
Transações de fragmentos e
Navegar entre fragmentos usando animações.
Chamar
addToBackStack()
confirma a transação na pilha de retorno. Posteriormente, o usuário pode reverter a
transação e recuperar o fragmento anterior pressionando o botão
Voltar. Se você adicionou ou removeu vários fragmentos em uma única
transação, todas essas operações serão desfeitas quando a pilha de retorno
for retirada. O nome opcional fornecido na chamada addToBackStack()
permite
retornar para essa transação específica usando
popBackStack()
.
Se você não chamar addToBackStack()
ao realizar uma transação que
remove um fragmento, ele será destruído quando a
transação for confirmada, e o usuário não poderá navegar de volta a ele. Se você
chamar addToBackStack()
ao remover um fragmento, ele será
apenas STOPPED
e, mais tarde, será RESUMED
quando o usuário navegar de volta. Observe que
a visualização está destruída nesse caso. Para ver mais informações, consulte
Ciclo de vida do fragmento.
Como encontrar um fragmento existente
Você pode conseguir uma referência ao fragmento atual em um contêiner de layout
usando
findFragmentById()
.
Use findFragmentById()
para procurar um fragmento pelo ID fornecido quando
inflado a partir do XML ou pelo ID do contêiner quando adicionado em uma
FragmentTransaction
. Veja um exemplo:
Kotlin
supportFragmentManager.commit { replace<ExampleFragment>(R.id.fragment_container) setReorderingAllowed(true) addToBackStack(null) } ... val fragment: ExampleFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as ExampleFragment
Java
FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.fragment_container, ExampleFragment.class, null) .setReorderingAllowed(true) .addToBackStack(null) .commit(); ... ExampleFragment fragment = (ExampleFragment) fragmentManager.findFragmentById(R.id.fragment_container);
Como alternativa, você pode atribuir uma tag exclusiva a um fragmento e conseguir uma
referência usando
findFragmentByTag()
.
É possível atribuir uma tag usando o atributo XML android:tag
em fragmentos
que são definidos no seu layout ou durante uma operação de add()
ou replace()
em uma FragmentTransaction
.
Kotlin
supportFragmentManager.commit { replace<ExampleFragment>(R.id.fragment_container, "tag") setReorderingAllowed(true) addToBackStack(null) } ... val fragment: ExampleFragment = supportFragmentManager.findFragmentByTag("tag") as ExampleFragment
Java
FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.fragment_container, ExampleFragment.class, null, "tag") .setReorderingAllowed(true) .addToBackStack(null) .commit(); ... ExampleFragment fragment = (ExampleFragment) fragmentManager.findFragmentByTag("tag");
Considerações especiais para fragmentos filhos e irmãos
Apenas um FragmentManager
tem permissão para controlar a pilha de retorno do fragmento
a qualquer momento. Se o app mostrar vários fragmentos irmãos na
tela ao mesmo tempo ou se ele usar fragmentos filhos, um
FragmentManager
precisará ser designado para processar a navegação principal do app.
Para definir o fragmento de navegação principal em uma transação de fragmento,
chame o
método setPrimaryNavigationFragment()
na transação, transmitindo na instância do fragmento cujo
childFragmentManager
precisa ter o controle principal.
Pense na estrutura de navegação como uma série de camadas, com a atividade como a camada mais externa, envolvendo cada camada de fragmentos filhos dentro dela. Cada camada precisa ter um único fragmento de navegação principal. Quando o evento de retorno ocorre, a camada mais interna controla o comportamento de navegação. Quando a camada mais interna não tem mais transações de fragmentos de onde retornar, o controle retorna à próxima camada externa, e esse processo é repetido até você chegar à atividade.
Quando dois ou mais fragmentos são exibidos ao mesmo tempo, apenas um deles pode ser o fragmento de navegação principal. Definir um fragmento como o de navegação principal remove a designação do fragmento anterior. Usando o exemplo anterior, se você definir o fragmento de detalhe como o de navegação principal, a designação do fragmento principal será removida.
Compatibilidade com várias backstacks
Em alguns casos, seu app pode precisar ser compatível com várias backstacks. Um exemplo
comum é quando o app usa uma barra de navegação inferior. FragmentManager
permite
que você seja compatível com várias backstacks com os métodos saveBackStack()
e
restoreBackStack()
. Esses métodos permitem alternar entre as backstacks
salvando uma pilha de retorno e restaurando outra diferente.
saveBackStack()
funciona de maneira semelhante a chamar popBackStack()
com o parâmetro opcional
name
: a transação especificada e todas as transações depois dela na
pilha são exibidas. A diferença é que saveBackStack()
salva o estado de todos os fragmentos nas transações
exibidas.
Por exemplo, suponha que você já tenha adicionado um fragmento à backstack
confirmando um FragmentTransaction
usando addToBackStack()
:
Kotlin
supportFragmentManager.commit { replace<ExampleFragment>(R.id.fragment_container) setReorderingAllowed(true) addToBackStack("replacement") }
Java
supportFragmentManager.beginTransaction() .replace(R.id.fragment_container, ExampleFragment.class, null) // setReorderingAllowed(true) and the optional string argument for // addToBackStack() are both required if you want to use saveBackStack(). .setReorderingAllowed(true) .addToBackStack("replacement") .commit();
Nesse caso, é possível salvar essa transação de fragmento e o estado de
ExampleFragment
chamando saveBackStack()
:
Kotlin
supportFragmentManager.saveBackStack("replacement")
Java
supportFragmentManager.saveBackStack("replacement");
É possível chamar restoreBackStack()
com o mesmo parâmetro de nome para restaurar todas
as transações exibidas e todos os estados do fragmento salvos:
Kotlin
supportFragmentManager.restoreBackStack("replacement")
Java
supportFragmentManager.restoreBackStack("replacement");
Fornecer dependências para seus fragmentos
Ao adicionar um fragmento, é possível instanciá-lo manualmente e
adicioná-lo à FragmentTransaction
.
Kotlin
fragmentManager.commit { // Instantiate a new instance before adding val myFragment = ExampleFragment() add(R.id.fragment_view_container, myFragment) setReorderingAllowed(true) }
Java
// Instantiate a new instance before adding ExampleFragment myFragment = new ExampleFragment(); fragmentManager.beginTransaction() .add(R.id.fragment_view_container, myFragment) .setReorderingAllowed(true) .commit();
Quando você confirma a transação do fragmento, a instância do fragmento
criado é a usada. No entanto, durante uma
mudança de configuração, sua
atividade e todos os fragmentos dela são destruídos e, em seguida, recriados com
os recursos Android
mais aplicáveis.
O FragmentManager
processa tudo isso para você. Ele recria instâncias
dos seus fragmentos, anexa-as ao host e recria o estado da
pilha de retorno.
Por padrão, o FragmentManager
usa um
FragmentFactory
fornecido pelo
framework para instanciar uma nova instância do seu fragmento. Essa
fábrica padrão usa reflexão para localizar e invocar um construtor sem argumento
para seu fragmento. Isso significa que não é possível usar essa fábrica padrão para
fornecer dependências para seu fragmento. Além disso, por padrão, qualquer construtor
personalizado usado para criar o fragmento na primeira vez não será usado
durante a recriação.
Para fornecer dependências ao seu fragmento ou usar qualquer
construtor personalizado, crie uma subclasse FragmentFactory
personalizada
e, em seguida, substitua
FragmentFactory.instantiate
.
Depois disso, você pode substituir a fábrica padrão do FragmentManager
pelo
factory personalizada, que será usado para instanciar seus fragmentos.
Imagine que você tem um DessertsFragment
responsável por exibir
sobremesas famosas na sua cidade natal. Vamos supor que DessertsFragment
tem uma dependência em uma classe DessertsRepository
que fornece as
informações necessárias para exibir a IU correta para o usuário.
Você pode definir seu DessertsFragment
para exigir uma instância
de DessertsRepository
no construtor.
Kotlin
class DessertsFragment(val dessertsRepository: DessertsRepository) : Fragment() { ... }
Java
public class DessertsFragment extends Fragment { private DessertsRepository dessertsRepository; public DessertsFragment(DessertsRepository dessertsRepository) { super(); this.dessertsRepository = dessertsRepository; } // Getter omitted. ... }
Uma implementação simples do seu FragmentFactory
pode ficar semelhante
a esta:
Kotlin
class MyFragmentFactory(val repository: DessertsRepository) : FragmentFactory() { override fun instantiate(classLoader: ClassLoader, className: String): Fragment = when (loadFragmentClass(classLoader, className)) { DessertsFragment::class.java -> DessertsFragment(repository) else -> super.instantiate(classLoader, className) } }
Java
public class MyFragmentFactory extends FragmentFactory { private DessertsRepository repository; public MyFragmentFactory(DessertsRepository repository) { super(); this.repository = repository; } @NonNull @Override public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) { Class<? extends Fragment> fragmentClass = loadFragmentClass(classLoader, className); if (fragmentClass == DessertsFragment.class) { return new DessertsFragment(repository); } else { return super.instantiate(classLoader, className); } } }
Esse exemplo de subclasses FragmentFactory
substitui o método
instantiate()
para fornecer uma lógica personalizada de criação de fragmentos para um DessertsFragment
.
Outras classes de fragmentos são processadas pelo comportamento padrão de
FragmentFactory
a super.instantiate()
.
Você pode designar MyFragmentFactory
como a fábrica a ser usada ao
construir os fragmentos do app definindo uma propriedade no
FragmentManager
. Defina essa propriedade antes do super.onCreate()
da atividade
para garantir que MyFragmentFactory
seja usado ao
recriar seus fragmentos.
Kotlin
class MealActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { supportFragmentManager.fragmentFactory = MyFragmentFactory(DessertsRepository.getInstance()) super.onCreate(savedInstanceState) } }
Java
public class MealActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { DessertsRepository repository = DessertsRepository.getInstance(); getSupportFragmentManager().setFragmentFactory(new MyFragmentFactory(repository)); super.onCreate(savedInstanceState); } }
Observe que a definição de FragmentFactory
na atividade substitui a criação de
fragmentos em toda a hierarquia de fragmentos da atividade. Em outras palavras,
o childFragmentManager
de todos os fragmentos filhos que você adiciona usa o conjunto de fábrica de fragmentos
personalizado mostrado aqui, a menos que seja substituído em um nível inferior.
Como testar com FragmentFactory
Em uma única arquitetura de atividade, teste os fragmentos em
isolamento usando a
classe
FragmentScenario
. Como não é possível confiar na lógica onCreate
personalizada da sua
atividade, você pode transmitir o FragmentFactory
como um argumento
para o teste de fragmentos, conforme mostrado no exemplo a seguir:
// Inside your test val dessertRepository = mock(DessertsRepository::class.java) launchFragment<DessertsFragment>(factory = MyFragmentFactory(dessertRepository)).onFragment { // Test Fragment logic }
Para ver informações detalhadas sobre esse processo de testagem e exemplos completos, consulte Testar os fragmentos do seu app.