Noções básicas sobre setRetainInstance do fragmento (booleano)

341

Começando com a documentação:

public void setRetainInstance (retenção booleana)

Controle se uma instância de fragmento é retida na recriação da atividade (como em uma alteração na configuração). Isso só pode ser usado com fragmentos que não estão na pilha de trás. Se definido, o ciclo de vida do fragmento será ligeiramente diferente quando uma atividade for recriada:

  • onDestroy () não será chamado (mas onDetach () ainda será, porque o fragmento está sendo desanexado de sua atividade atual).
  • onCreate (Bundle) não será chamado, pois o fragmento não está sendo recriado.
  • onAttach (Activity) e onActivityCreated (Bundle) ainda serão chamados.

Eu tenho algumas questões:

  • O fragmento também mantém sua visão, ou isso será recriado na alteração da configuração? O que exatamente significa "retido"?

  • O fragmento será destruído quando o usuário sair da atividade?

  • Por que não funciona com fragmentos na pilha traseira?

  • Quais são os casos de uso em que faz sentido usar esse método?

Ixx
fonte
4
pergunta semelhante com informações boas: Por que usar o fragmento # setRetainInstance (boolean)?
Richard Le Mesurier

Respostas:

348

Primeiro de tudo, confira meu post sobre fragmentos retidos. Isso pode ajudar.

Agora, para responder às suas perguntas:

O fragmento também mantém seu estado de exibição , ou isso será recriado na alteração da configuração - o que exatamente é "retido"?

Sim, o Fragmentestado do será retido durante a alteração da configuração. Especificamente, "retido" significa que o fragmento não será destruído nas alterações de configuração. Ou seja, a retençãoFragment será mantida mesmo se a alteração na configuração fizer com que o subjacente Activityseja destruído.

O fragmento será destruído quando o usuário sair da atividade?

Assim como Activitys, Fragments pode ser destruído pelo sistema quando os recursos de memória estão baixos. Se seus fragmentos mantêm seu estado de instância nas alterações de configuração, não terá efeito se o sistema destruirá os sistemas Fragmentassim que você sair Activity. Se você sair do Activity(ou seja, pressionando o botão home), os Fragments podem ou não ser destruídos. Se você sair Activitypressionando o botão voltar (assim, chamando finish()e destruindo efetivamente o Activity), todos os Activitys anexados Fragmenttambém serão destruídos.

Por que não funciona com fragmentos na pilha traseira?

Provavelmente, existem várias razões pelas quais não é suportado, mas a razão mais óbvia para mim é que o Activitydetém uma referência ao FragmentManagere FragmentManagergerencia o backstack. Ou seja, não importa se você optar por manter seus Fragmentou não, o Activity(e, portanto, o FragmentManagerbackstack) será destruído em uma alteração na configuração. Outra razão pela qual isso pode não funcionar é que as coisas podem ficar complicadas se os fragmentos retidos e os não retidos puderem existir no mesmo backstack.

Quais são os casos de uso em que faz sentido usar esse método?

Fragmentos retidos podem ser bastante úteis para propagar informações de estado - especialmente gerenciamento de encadeamentos - entre instâncias de atividade. Por exemplo, um fragmento pode servir como host para uma instância de Threadou AsyncTask, gerenciando sua operação. Veja minha postagem no blog sobre este tópico para obter mais informações.

Em geral, eu o trataria da mesma forma que o uso onConfigurationChangedcom um Activity... não o use como um bandaid apenas porque você é muito preguiçoso para implementar / lidar com uma alteração de orientação corretamente. Use-o somente quando precisar.

Alex Lockwood
fonte
37
Os objetos de exibição não são mantidos, eles são sempre destruídos nas alterações de configuração.
Markus Junginger
103
Pelo que sei, se você tiver setRetainInstance(true), o Fragmentobjeto java e todo o seu conteúdo não são destruídos na rotação, mas a exibição é recriada. Isso é onCreatedView()chamado novamente. É basicamente o jeito que deveria funcionar Activitiesdesde o Android 1.0. Eu não acho que seja "preguiçoso" usá-lo, ou usá-lo não é "adequado". Na verdade, não consigo ver por que não é o padrão ou por que você iria querer isso.
Timmmm
24
Encontrei sua explicação para "Por que não funciona com fragmentos na pilha traseira?" difícil de entender. Mas talvez eu seja burro :(
HGPB 19/10/12
13
@dierre Uma atividade pode ser destruída de várias maneiras. Por exemplo, se você clicar em "voltar", a atividade será destruída. Se você clicar em "casa", a atividade será interrompida e, em algum momento no futuro, poderá ser destruída quando a memória estiver baixa. Os retidos Fragmentsão retidos apenas nas alterações de configuração, onde a atividade subjacente deve ser destruída e recriada imediatamente. Em todos os outros casos em que a atividade é destruída, os fragmentos retidos também serão destruídos.
Alex Lockwood
3
@AlexLockwood, você pode confirmar o seguinte: Mesmo sendo setRetainInstance(true)usado, ainda é necessário implementar sua própria persistência ( savedInstanceStateou não) para poder lidar com todos os cenários: por exemplo, "tecla home, girar, voltar ao aplicativo" recria meu fragmento com o construtor chamada, perdendo todas as variáveis ​​de estado. Eu tenho uma AsyncTaskvariável como membro, é por isso que quero reter, agora, se quiser que funcione, sou forçado a interromper a tarefa, salvar o estado e retomar quando o usuário voltar. Portanto, apesar de tudo, essa é apenas uma maneira rápida de ajudar na rotação, mas, de outra forma, inútil em geral.
TWIStErRob 5/05
28

setRetaininstancesó é útil quando você activityé destruído e recriado devido a uma alteração na configuração porque as instâncias são salvas durante uma chamada para onRetainNonConfigurationInstance. Ou seja, se você girar o dispositivo, os fragmentos retidos permanecerão lá (eles não serão destruídos e recriados.) Mas quando o tempo de execução interrompe a atividade para recuperar recursos, nada resta. Quando você pressiona o botão Voltar e sai da atividade, tudo é destruído.

Normalmente, eu uso essa função para salvar a orientação, alterando o Time. Diga que tenho que baixar um monte de Bitmaps do servidor e cada um tem 1 MB, quando o usuário acidentalmente gira o dispositivo, certamente não quero fazer todo o trabalho de download novamente. Crio uma Fragmentretenção dos meus bitmaps e os adiciono ao gerente e à chamada setRetainInstance. Todos os bitmaps ainda estão lá, mesmo que a orientação da tela seja alterada.

suitianshi
fonte
Você cria fragmentos "Somente dados" (sem nenhum widget) apenas como suporte para seus bitmaps ou esses fragmentos também podem ter widgets? Eu li algo sobre o perigo de produção de vazamentos de memória quando o fragmento contém algo relacionado ao contexto / Atividade ...
hgoebl
A estrutura limpará a mActivityreferência para você. Mas não sei se o tempo de execução também limparia widgets na instância de fragmento nesse caso. Por favor, experimente ou mergulhe no código fonte.
suitianshi
Bom exemplo de quando podemos usar o setRetaininstance
Mu Sa
12

SetRetainInstance (true) permite que o tipo de fragmento sobreviva. Seus membros serão retidos durante a alteração da configuração, como rotação. Mas ainda pode ser morto quando a atividade é morta em segundo plano. Se a atividade que contém o plano de fundo for eliminada pelo sistema, o instanceState deverá ser salvo pelo sistema que você tratou no SaveInstanceState corretamente. Em outra palavra, o onSaveInstanceState sempre será chamado. Embora onCreateView não seja chamado se SetRetainInstance for true e o fragmento / atividade ainda não for eliminado, ele ainda será chamado se for eliminado e tentar ser recuperado.

Aqui estão algumas análises da atividade / fragmento do Android, espero que ajude. http://ideaventure.blogspot.com.au/2014/01/android-activityfragment-life-cycle.html

Kejun Xia
fonte
7
Definitivamente, estou vendo o onCreateView ser chamado novamente no fragmento retido ao girar a tela.
aij
Este link é seu próprio blog? Você deve deixar isso claro, se for esse o caso.
Flexo
4

setRetainInstance () - Descontinuado

Como fragmentos versão 1.3.0-alpha01

O método setRetainInstance () em Fragments foi preterido. Com a introdução do ViewModels, os desenvolvedores têm uma API específica para manter o estado que pode ser associado aos gráficos de atividades, fragmentos e navegação. Isso permite que os desenvolvedores usem um Fragmento normal, não retido, e mantenham separados o estado específico que desejam reter, evitando uma fonte comum de vazamentos, mantendo as propriedades úteis de uma única criação e destruição do estado retido (ou seja, o construtor do ViewModel e o retorno de chamada onCleared () que recebe).

Gastón Saillén
fonte
2

setRetainInstance (boolean) é útil quando você deseja ter algum componente que não esteja vinculado ao ciclo de vida da atividade. Essa técnica é usada, por exemplo, pelo rxloader para "manipular o ciclo de vida da atividade do Android para o Observable do rxjava" (que eu encontrei aqui ).

Marian Paździoch
fonte