Eu estava passando pelo site do desenvolvedor Android, atualizando sobre o ciclo de vida da atividade e, em cada exemplo de código, há um comentário ao lado dos métodos da superclasse que diz "Sempre chame o método da superclasse primeiro".
Embora isso faça sentido no meio ciclo de criação: onCreate, onStart e onResume, estou um pouco confuso quanto ao procedimento correto no meio ciclo de destruição: onPause, onStop, onDestroy.
Destruir os recursos específicos da instância primeiro, antes de destruir os recursos da superclasse dos quais os recursos específicos da instância podem depender, faz sentido, e não o contrário. Mas os comentários sugerem o contrário. o que estou perdendo?
Edit : Uma vez que as pessoas parecem estar ficando confusas quanto à intenção da pergunta, o que eu quero saber é qual das opções a seguir é a correta? E PORQUE ?
1. O Google sugere
@Override
protected void onStop() {
super.onStop(); // Always call the superclass method first
//my implementation here
}
2.O outro jeito
@Override
protected void onStop() {
//my implementation here
super.onStop();
}
fonte
Respostas:
Na minha opinião: nem uma coisa.
Esta resposta de Mark (também conhecido como CommonsWare no SO) lança luz sobre a questão: Link - A chamada para o método da superclasse deve ser a primeira instrução? . Mas então, você pode ver o seguinte comentário deixado em sua resposta:
De volta à estaca zero. Ok, vamos ver isso de outro ângulo. Sabemos que a Especificação da linguagem Java não especifica uma ordem na qual a chamada
super.overridenMethod()
deve ser feita (ou se a chamada deve ser feita).No caso da classe Activity, as
super.overridenMethod()
chamadas são necessárias e aplicadas :mCalled
está definido como verdadeiro emActivity.onStop()
.Agora, o único detalhe que resta para debater é o pedido.
I also know that both work
Certo. Observe o corpo do método para Activity.onPause ():
Seja qual for a maneira que você imprensar a chamada
super.onPause()
, você estará bem. Activity.onStop () tem um corpo de método semelhante. Mas dê uma olhada em Activity.onDestroy ():Aqui, a ordem pode ser importante dependendo de como sua atividade está configurada e se a chamada
super.onDestroy()
interfere no código a seguir.Como uma palavra final, a declaração
Always call the superclass method first
não parece ter muitas evidências para apoiá-la. O que é pior (para a declaração) é que o seguinte código foi extraído deandroid.app.ListActivity
:E, no aplicativo de amostra LunarLander incluído no SDK do Android:
Resumo e menções dignas:
Usuário Philip Sheard : Fornece um cenário onde uma chamada para
super.onPause()
deve ser adiada em caso de uma atividade começou a usarstartActivityForResult(Intent)
. Definir o resultado usandosetResult(...)
depoissuper.onPause()
não funcionará. Posteriormente, ele esclarece isso nos comentários à sua resposta.Usuário Sherif elKhatib : explica por que deixar a superclasse inicializar seus recursos primeiro e destruí- los por último segue a lógica:
Ele prossegue apontando: se uma classe filha for adequadamente isolada (em termos de dependência de recursos) da classe pai, as
super.X()
chamadas não precisam aderir a nenhuma especificação de ordem.Veja a resposta nesta página para ler através de um cenário em que a colocação de
super.onDestroy()
chamada não afeta a lógica do programa.De uma resposta de Mark :
Bob Kerns de esta discussão :
O usuário Steve Benett também chama a atenção para isso:
O usuário Sunil Mishra confirma que a ordem (mais provavelmente) não desempenha um papel ao chamar os métodos da classe Activity. Ele também afirma que chamar os métodos da superclasse primeiro é considerado uma prática recomendada . No entanto, não pude corroborar isso.
Usuário LOG_TAG : explica por que uma chamada para o construtor da superclasse precisa ser antes de tudo. Em minha opinião, esta explicação não acrescenta nada à pergunta que está sendo feita.
Nota final : confie, mas verifique. A maioria das respostas nesta página segue esta abordagem para ver se a declaração
Always call the superclass method first
tem um apoio lógico. Acontece que não; pelo menos, não no caso da classe Activity. Geralmente, deve-se ler o código-fonte da superclasse para determinar se ordenar chamadas para os métodos de super é um requisito.fonte
onDestroy
eonStop
último é um padrão mais seguro e que para asonPause
coisas pode ser mais complicado em alguns casos? Você poderia adicionar isso primeiro? Fiquei tentado a editar a resposta sozinho, mas não tenho certeza se este resumo está correto.Já que (você diz) faz sentido chamar super onCreate primeiro: Pense nisso.
Quando eu quero criar, Meu super cria seus recursos> Eu crio meus recursos.
Inversamente: (uma espécie de pilha)
Quando eu quero destruir, eu destruo meus recursos> Meu super destrói seus recursos.
Nesse sentido, ele se aplica a qualquer par de funções (onCreate / onDestroy, onResume / onPause, onStart / onStop). Naturalmente, onCreate criará recursos e onDestroy irá liberar esses recursos. Aliás, a mesma prova vale para os outros casais.
Vamos considerar uma biblioteca que você baixou que tem um LocationActivity que contém uma função getLocation () que fornece o local. Muito provavelmente, esta atividade precisará inicializar seu material no onCreate (), o que o forçará a chamar o super.onCreate primeiro. Você já faz isso porque sente que faz sentido. Agora, em seu onDestroy, você decide que deseja salvar o local em algum lugar em SharedPreferences. Se você chamar super.onDestroy primeiro, é até certo ponto possível que getLocation retorne um valor nulo após essa chamada porque a implementação de LocationActivity anula o valor de local em onDestroy. A ideia é que você não culparia se isso acontecesse. Portanto, você chamaria super.onDestroy no final, depois de concluir o seu próprio onDestroy. Espero que isso faça algum sentido.
Se o exposto acima fizer sentido, considere que a qualquer momento temos uma atividade que segue o conceito acima. Se eu quiser estender esta atividade, provavelmente vou me sentir da mesma maneira e seguir a mesma ordem por causa do mesmo argumento exato.
Por indução, qualquer atividade deve fazer a mesma coisa. Aqui está uma boa classe abstrata para uma atividade forçada a seguir estas regras:
Finalmente, e se sua atividade chamada
AnudeepBullaActivity
estende BaseActivity e, posteriormente, eu quero criarSherifElKhatibActivity
que estende sua atividade? Em que ordem devo chamar assuper.do
funções? Em última análise, é a mesma coisa.Quanto à sua pergunta:
Acho que a intenção do Google é nos dizer: ligue para o supervisor, não importa onde. Como uma prática geral, é claro, chame-o no início. O Google, é claro, tem os engenheiros e desenvolvedores mais brilhantes, então eles provavelmente fizeram um bom trabalho ao isolar suas super chamadas e não interferir nas chamadas secundárias.
Tentei um pouco e provavelmente não é fácil (já que é o Google que estamos tentando provar que estamos errados) criar uma atividade que travaria simplesmente por causa de When está sendo super chamado.
Por quê?
Qualquer coisa feita nessas funções é realmente privada para a classe Activity e nunca causaria qualquer conflito com sua subclasse. Por exemplo (onDestroy)
mManagedCursors e mManagedDialogs e mSearchManager são todos campos privados. E nenhuma API pública / protegida será afetada pelo que é feito aqui.
No entanto, na API 14, dispatchActivityDestroyed foi adicionado para despachar um onActivityDestroyed para ActivityLifecycleCallbacks registrados em seu aplicativo. Portanto, qualquer código que dependa de alguma lógica em ActivityLifecycleCallbacks terá um resultado diferente com base em quando você está chamando o super. Por exemplo:
Crie uma classe de aplicativo que conte o número de atividades em execução no momento:
O seguinte pode não fazer sentido ou não ser uma boa prática, mas é apenas para provar um ponto (pode-se encontrar uma situação mais real). Crie a MainActivity que supostamente vai para a atividade GoodBye quando for concluída e quando for a última atividade:
Se você chamar super.onDestroy no início de seu onDestroy, a atividade GoodBye será iniciada. Se você chamar super.onDestroy no final de seu onDestroy, a atividade GoodBye não será iniciada.
Claro, novamente, este não é o exemplo ideal. No entanto, isso mostra que o Google bagunçou um pouco aqui. Qualquer uma das outras variáveis não teria afetado o comportamento do seu aplicativo. No entanto, adicionar esses despachos ao onDestroy fazia com que o super interferisse de alguma forma em sua subclasse.
Eu digo que eles bagunçaram por um motivo diferente também. Eles não apenas (antes da api 14) apenas tocavam nas super chamadas o que é final e / ou privado, mas também chamavam diferentes funções internas (privadas) que realmente despachavam as funções onPause ....
Por exemplo,
performStop
function é a função chamada que, por sua vez, chama a função onStop:Observe que eles chamam onStop da atividade em algum lugar desta função. Portanto, eles também podem ter colocado todo o código (incluído em super.onStop) antes ou depois da chamada para onStop e, em seguida, apenas notificar as subclasses sobre onStop usando superfunções onStop vazias e sem nem mesmo adicionar a SuperNotCalledException ou verificar se ela foi chamada.
Para isso, se eles chamaram esse despacho para ActivityLifeCycle em performDestroy em vez de chamá-lo no final de super.onDestroy, o comportamento de nossa atividade teria sido o mesmo, independentemente de quando chamamos o super.
De qualquer forma esta é a primeira coisa que eles fazem (um pouco errado) e é apenas na API 14.
fonte
super.on
provavelmente nunca irá travar sua atividade.Da perspectiva do java, aqui está uma solução para essa confusão:
Por que this () e super () precisam ser a primeira instrução em um construtor?
O construtor da classe pai precisa ser chamado antes do construtor da subclasse. Isso garantirá que, se você chamar qualquer método na classe pai em seu construtor, a classe pai já foi configurada corretamente.
O que você está tentando fazer, passar args para o super construtor é perfeitamente legal, você só precisa construir esses args inline conforme está fazendo ou passá-los para o seu construtor e depois passá-los para super:
Se o compilador não aplicasse isso, você poderia fazer o seguinte:
Isso mostra que, na verdade, os subcampos devem ser inicializados antes da supra-classe! Enquanto isso, o requisito de java nos "defende" de especializar a classe por especializar o que o argumento do super construtor
Nos casos em que uma classe pai tem um construtor padrão, a chamada a super é inserida para você automaticamente pelo compilador. Visto que toda classe em Java herda de Object, o construtor de objetos deve ser chamado de alguma forma e deve ser executado primeiro. A inserção automática de super () pelo compilador permite isso. Forçar que super apareça primeiro, obriga que os corpos do construtor sejam executados na ordem correta, que seria: Objeto -> Pai -> Filho -> ChildOfChild -> SoOnSoForth
(1) Verificar se super é a primeira afirmação não é suficiente para evitar esse problema. Por exemplo, você pode colocar "super (someMethodInSuper ());" em seu construtor. Isso tenta acessar um método na superclasse antes de ser construído, mesmo que super seja a primeira instrução.
(2) O compilador parece implementar uma verificação diferente que é, por si só, suficiente para evitar esse problema. A mensagem é "não é possível fazer referência a xxx antes que o construtor de supertipo seja chamado". Portanto, verificar se super é a primeira afirmação não é necessário
Acesse http://valjok.blogspot.in/2012/09/super-constructor-must-be-first.html
fonte
A coisa mais importante a ter em mente é que
super.onPause()
chama implicitamentesetResult(Activity.RESULT_CANCELED)
. MassetResult
só pode ser chamado uma vez e todas as chamadas subsequentes são ignoradas. Portanto, se você quiser devolver qualquer tipo de resultado à atividade dos pais, terá de ligar parasetResult
si mesmo antes de ligarsuper.onPause()
. Esse é o maior problema, até onde eu sei.fonte
super.onPause() implicitly calls setResult(Activity.RESULT_CANCELED)
. Você poderia dizer de onde você tirou isso?AMBOS estão corretos OMI
De acordo com os docs
Super
método deve sempre ser chamado quando a documentação diz explicitamente isso.No entanto, você pode escolher quando chamar o método super.
Olhando para a fonte de
onPause
Portanto, não importa antes ou depois de ser chamado. Você deve ser bom.
Mas, para melhores práticas, você deve ligar primeiro.
Eu o recomendo principalmente como um mecanismo de proteção: se houver uma exceção, o
super
método de instância já terá sido chamado.Além disso, colocar essas chamadas na primeira linha ajudará você a evitar cometer erros no futuro, como excluir o código do método e acidentalmente excluir a chamada para a superclasse.
fonte
Base Class
mas se você substituir, é necessário que você chame osuper
outro que você teráandroid.app.SuperNotCalledException
Você diz que o Google sugere o método 1, mas Dianne Hackborn, uma conhecida engenheira de framework do Android, sugere o contrário, consulte o link do Google Forum .
Faz sentido intuitivamente chamar a superclasse por último ao destruir uma instância nos métodos onPause, onStop e onDestroy e primeiro ao criar uma instância com os métodos onCreate, onResume e onStart .
fonte
O super dos retornos de chamada é necessário para colocar a Activity no estado correto internamente para o sistema.
Digamos que você inicie sua Activity e onCreate seja invocado pelo sistema. Agora você pode substituí-lo e, por exemplo, carregar seu layout. Mas, para o fluxo do sistema, você deve chamar super, para que o sistema possa continuar com o procedimento padrão. É por isso que uma exceção será lançada se você não chamá-la.
Isso acontece independentemente de sua implementação em onCreate. É apenas importante para o sistema. Se não houvesse ANR, você poderia ter um loop infinito em qualquer retorno de chamada e a Activity seria capturada naquele. Assim, o sistema sabe quando o retorno de chamada foi encerrado e então chama o próximo.
Eu só conheço uma situação, em que o momento da super chamada é necessário. Se você quiser alterar o comportamento padrão do tema ou da tela e outros itens em onCreate, terá que fazer isso antes de chamar super para ver um efeito. Caso contrário, AFAIK não há diferença em que momento você chama.
Mas para deixar o sistema fazer o que pode melhor, colocar o super na primeira linha de um retorno de chamada seguido pelo seu código, se você não tiver um bom motivo para romper com ele.
fonte