Qual é a ordem correta de chamada dos métodos da superclasse nos métodos onPause, onStop e onDestroy? e porque?

89

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();  
    }
Anudeep Bulla
fonte
1
Estou no campo dois pelos métodos de desligamento. Estou no acampamento um para métodos de inicialização.
danny117
1
Esse é o ponto principal. Simplesmente não conseguia entender como o uso do método 1 para métodos de desligamento fazia sentido.
Anudeep Bulla

Respostas:

107

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?

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:

Mas por que o documento oficial diz: "Sempre chame o método da superclasse primeiro" em onPause ()?

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 :

if (!mCalled) {
    throw new SuperNotCalledException(
        "Activity " + mComponent.toShortString() +
            " did not call through to super.onStop()");
}

mCalledestá definido como verdadeiro em Activity.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 ():

protected void onPause() {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this);

    // This is to invoke 
    // Application.ActivityLifecyleCallbacks.onActivityPaused(Activity)
    getApplication().dispatchActivityPaused(this);

    // The flag to enforce calling of this method
    mCalled = true;
}

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 ():

protected void onDestroy() {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
    mCalled = true;

    // dismiss any dialogs we are managing.
    if (mManagedDialogs != null) {
        final int numDialogs = mManagedDialogs.size();
        for (int i = 0; i < numDialogs; i++) {
            final ManagedDialog md = mManagedDialogs.valueAt(i);
            if (md.mDialog.isShowing()) {
                md.mDialog.dismiss();
            }
        }
        mManagedDialogs = null;
    }

    // close any cursors we are managing.
    synchronized (mManagedCursors) {
        int numCursors = mManagedCursors.size();
        for (int i = 0; i < numCursors; i++) {
            ManagedCursor c = mManagedCursors.get(i);
            if (c != null) {
                c.mCursor.close();
            }
        }
        mManagedCursors.clear();
    }

    // Close any open search dialog
    if (mSearchManager != null) {
        mSearchManager.stopSearch();
    }

    getApplication().dispatchActivityDestroyed(this);
}

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 firstnão parece ter muitas evidências para apoiá-la. O que é pior (para a declaração) é que o seguinte código foi extraído de android.app.ListActivity:

public class ListActivity extends Activity {

    ....

    @Override
    protected void onDestroy() {
        mHandler.removeCallbacks(mRequestFocus);
        super.onDestroy();
    }
    ....    
}

E, no aplicativo de amostra LunarLander incluído no SDK do Android:

public class LunarLander extends Activity {

    ....

    @Override
    protected void onPause() {
        mLunarView.getThread().pause(); // pause game when Activity pauses
        super.onPause();
    }
    ....
}

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 usar startActivityForResult(Intent). Definir o resultado usando setResult(...) depois super.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:

Vamos considerar uma biblioteca que você baixou que tem uma LocationActivity que contém uma função getLocation () que fornece a localização. 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 acha 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 localização 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.

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 :

Métodos que você substitui que fazem parte da criação do componente (onCreate (), onStart (), onResume (), etc.), você deve encadear a superclasse como a primeira instrução , para garantir que o Android tenha a chance de fazer seu trabalho antes de você tentativa de fazer algo que depende do trabalho ter sido feito.

Métodos que você sobrescreve que fazem parte da destruição de componentes (onPause (), onStop (), onDestroy (), etc.), você deve fazer seu trabalho primeiro e encadear para a superclasse como a última coisa . Dessa forma, no caso de o Android limpar algo de que depende o seu trabalho, você terá feito seu trabalho primeiro.

Métodos que retornam algo diferente de void (onCreateOptionsMenu (), etc.), às vezes você encadeia com a superclasse na instrução return, assumindo que você não está fazendo algo especificamente que precise forçar um valor de retorno específico.

Todo o resto - como onActivityResult () - é com você, como um todo. Eu tendo a encadear para a superclasse como a primeira coisa, mas a menos que você esteja tendo problemas, encadear depois deve ser suficiente.

Bob Kerns de esta discussão :

É um bom padrão [(o padrão que Mark sugere acima)], mas encontrei algumas exceções. Por exemplo, o tema que eu queria aplicar à minha PreferenceActivity não entraria em vigor a menos que eu o colocasse antes do onCreate () da superclasse.

O usuário Steve Benett também chama a atenção para isso:

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.

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 firsttem 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.

Vikram
fonte
2
Uau. Obrigado pelas dicas. Ambas as respostas, esta e @Sherif, fornecem um contexto importante. Se algum de vocês puder resumir as respostas desta página, eu marcarei como aceito. Por favor, inclua: 1.Respostas nesta página. 2. Resposta de @Philip nesta página 3. Resposta de @ CommonsWare nesta página 4. Esta discussão eu gostaria, mas não quero os créditos por suas maravilhosas respostas. Cheers & Thanks
Anudeep Bulla
Oi. Você poderia resumir, visto que @Sherif não quer?
Anudeep Bulla
@AnudeepBulla Oi Anudeep, dê-me até amanhã. Vou adicionar o material relevante à minha resposta e deixar um comentário aqui.
Vikram
@AnudeepBulla Eu adicionei um resumo acima. Por favor, me avise caso eu tenha perdido alguma coisa.
Vikram
@Vikram é o TL; DR. que chamar onDestroye onStopúltimo é um padrão mais seguro e que para as onPausecoisas 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.
Blaisorblade
12

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:

package mobi.sherif.base;

import android.app.Activity;
import android.os.Bundle;

public abstract class BaseActivity extends Activity {
    protected abstract void doCreate(Bundle savedInstanceState);
    protected abstract void doDestroy();
    protected abstract void doResume();
    protected abstract void doPause();
    protected abstract void doStart();
    protected abstract void doStop();
    protected abstract void doSaveInstanceState(Bundle outState);
    @Override
    protected final void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        doCreate(savedInstanceState);
    }
    @Override
    protected final void onDestroy() {
        doDestroy();
        super.onDestroy();
    }
    @Override
    protected final void onResume() {
        super.onResume();
        doResume();
    }
    @Override
    protected final void onPause() {
        doPause();
        super.onPause();
    }
    @Override
    protected final void onStop() {
        doStop();
        super.onStop();
    }
    @Override
    protected final void onStart() {
        super.onStart();
        doStart();
    }
    @Override
    protected final void onSaveInstanceState(Bundle outState) {
        doSaveInstanceState(outState);
        super.onSaveInstanceState(outState);
    }
}

Finalmente, e se sua atividade chamada AnudeepBullaActivityestende BaseActivity e, posteriormente, eu quero criar SherifElKhatibActivityque estende sua atividade? Em que ordem devo chamar as super.dofunçõ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)

protected void onDestroy() {
    if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
    mCalled = true;

    // dismiss any dialogs we are managing.
    if (mManagedDialogs != null) {
        final int numDialogs = mManagedDialogs.size();
        for (int i = 0; i < numDialogs; i++) {
            final ManagedDialog md = mManagedDialogs.valueAt(i);
            if (md.mDialog.isShowing()) {
                md.mDialog.dismiss();
            }
        }
        mManagedDialogs = null;
    }

    // close any cursors we are managing.
    synchronized (mManagedCursors) {
        int numCursors = mManagedCursors.size();
        for (int i = 0; i < numCursors; i++) {
            ManagedCursor c = mManagedCursors.get(i);
            if (c != null) {
                c.mCursor.close();
            }
        }
        mManagedCursors.clear();
    }

    // Close any open search dialog
    if (mSearchManager != null) {
        mSearchManager.stopSearch();
    }

    getApplication().dispatchActivityDestroyed(this);
}

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:

package mobi.shush;

import android.app.Activity;
import android.app.Application;
import android.app.Application.ActivityLifecycleCallbacks;
import android.os.Bundle;

public class SherifApplication extends Application implements ActivityLifecycleCallbacks {
    @Override
    public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(this);
    }
    public int getCount() {
        return count;
    }
    int count = 0;
    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        count++;
    }
    @Override
    public void onActivityDestroyed(Activity activity) {
        count--;
    }
    @Override
    public void onActivityPaused(Activity activity) {}
    @Override
    public void onActivityResumed(Activity activity) {}
    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState)           {}
    @Override
    public void onActivityStarted(Activity activity) {}
    @Override
    public void onActivityStopped(Activity activity) {}
}

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:

@Override
protected void onDestroy() {
    super.onDestroy();
    if(((SherifApplication) getApplication()).getCount() == 0) {
        //i want to go to a certain activity when there are no other activities
        startActivity(new Intent(this, GoodBye.class));
    }
}

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, performStopfunction é a função chamada que, por sua vez, chama a função onStop:

final void performStop() {
    if (mLoadersStarted) {
        mLoadersStarted = false;
        if (mLoaderManager != null) {
            if (!mChangingConfigurations) {
                mLoaderManager.doStop();
            } else {
                mLoaderManager.doRetain();
            }
        }
    }

    if (!mStopped) {
        if (mWindow != null) {
            mWindow.closeAllPanels();
        }

        if (mToken != null && mParent == null) {
            WindowManagerGlobal.getInstance().setStoppedState(mToken, true);
        }

        mFragments.dispatchStop();

        mCalled = false;
        mInstrumentation.callActivityOnStop(this);
        if (!mCalled) {
            throw new SuperNotCalledException(
                    "Activity " + mComponent.toShortString() +
                    " did not call through to super.onStop()");
        }

        synchronized (mManagedCursors) {
            final int N = mManagedCursors.size();
            for (int i=0; i<N; i++) {
                ManagedCursor mc = mManagedCursors.get(i);
                if (!mc.mReleased) {
                    mc.mCursor.deactivate();
                    mc.mReleased = true;
                }
            }
        }

        mStopped = true;
    }
    mResumed = false;
}

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.

Sherif elKhatib
fonte
A questão nunca foi por que chamar super.onDestroy () por último faz sentido. Eu amo seu exemplo de biblioteca. Exatamente o que eu queria transmitir também. Eu não poderia concordar mais em chamar super métodos por último nos últimos meio ciclos de destruição, exatamente como em uma pilha, para evitar perda acidental de dados. O problema é por que o Google insiste em chamar supermétodos primeiro, dada a premissa acima? Fiz a pergunta porque pensei que talvez eu, e aparentemente você também, estivesse abordando a questão de forma completamente diferente. Saúde
Anudeep Bulla
Ah eu não vi o Google sugere e o outro jeito: p! Escute, vou tentar criar uma atividade que travará se você ligar para Destroy primeiro. Você deveria tentar isso também. Saúde
Sherif elKhatib de
@AnudeepBulla você pode verificar minhas edições. E btw você pode parar de tentar. super.onprovavelmente nunca irá travar sua atividade.
Sherif elKhatib de
Uau. Obrigado pelas dicas. Ambas as respostas, esta e @Usuário fornecem um contexto importante. Se algum de vocês puder resumir as respostas desta página, eu marcarei como aceito. Por favor, inclua: 1.Respostas nesta página. 2. Resposta de @Philip nesta página 3. Resposta de @ CommonsWare nesta página 4. Esta discussão eu gostaria, mas não quero os créditos por suas maravilhosas respostas. Saudações e agradecimentos
Anudeep Bulla
@AnudeepBulla De nada. Não tenho certeza de como vamos decidir quem publica o artigo final.
Vikram
1

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:

public MySubClassB extends MyClass {
        public MySubClassB(Object[] myArray) {
                super(myArray);
        }
}

Se o compilador não aplicasse isso, você poderia fazer o seguinte:

public MySubClassB extends MyClass {
        public MySubClassB(Object[] myArray) {
                someMethodOnSuper(); //ERROR super not yet constructed
                super(myArray);
        }
}

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

LOG_TAG
fonte
Eu entendo perfeitamente o que você está colocando aí. Você chama os construtores de superclasse primeiro, porque eles podem inicializar os recursos de que a criança pode precisar; e os destruidores duram, porque você provavelmente não quer apagar todos os pais para os recursos locais, tornando-os inúteis. Esse é exatamente o meu ponto. E uma vez que onPause, onStop e onDestroy têm a função de salvar informações de estado e mais ou menos disponibilizar recursos para GC (portanto, em certo sentido, destruí-los), vejo-os análogos aos destruidores e, portanto, acho que chamá-los por último faz sentido. Não?
Anudeep Bulla de
Tudo o que você disse acima é exatamente o que eu quis dizer quando disse "chamar supermétodos primeiro faz sentido no meio-ciclo de criação". Estou preocupado e confuso no caso dos métodos de meio ciclo de destruição, que parecem mais análogos aos destruidores. Saúde
Anudeep Bulla de
1

A coisa mais importante a ter em mente é que super.onPause()chama implicitamente setResult(Activity.RESULT_CANCELED). Mas setResultsó 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 para setResultsi mesmo antes de ligar super.onPause(). Esse é o maior problema, até onde eu sei.

Philip Sheard
fonte
Uau, isso parece importante. Portanto, há uma situação em que você definitivamente precisa atrasar a chamada para os métodos super. Obrigado.
Anudeep Bulla de
super.onPause() implicitly calls setResult(Activity.RESULT_CANCELED). Você poderia dizer de onde você tirou isso?
Vikram
Eu estava confuso. Na verdade, é finish () que chama setResult, e super.onBackPressed () chama finish (). Portanto, setResult definitivamente deve ser chamado antes de super.onBackPressed (). Não tenho certeza se há alguma circunstância em que super.onPause () possa fazer com que setResult seja chamado, mas prefiro não arriscar.
Philip Sheard
1

AMBOS estão corretos OMI

De acordo com os docs

As classes derivadas devem chamar a implementação da superclasse desse método. Caso contrário, uma exceção será lançada.

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

protected void onPause() {
    getApplication().dispatchActivityPaused(this);
    mCalled = true;
}

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 supermé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.

Sunil Mishra
fonte
Lamento se a questão não ficou totalmente clara da primeira vez, mas por favor, dê uma olhada agora.
Anudeep Bulla de
@AnudeepBulla Isso é o que eu expliquei para você. Você pode usar qualquer um deles. Ambos são válidos.
Sunil Mishra
É meu entendimento que a implementação personalizada dos métodos onPause, onStop e onDestroy não é estritamente necessária. Fiz muitos aplicativos sem eles. Então, o que você quer dizer com métodos Super devem sempre ser chamados? Eles são chamados implicitamente, mesmo sem substituir. Eu também sei que ambos funcionam. Quero saber por que os médicos dizem que o supervisor deve ser chamado primeiro. E caso a pergunta ainda não seja aparente, você poderia explicar POR QUE, quando disser "Mas para melhores práticas, você deveria ligar primeiro"?
Anudeep Bulla
Se você não substituir, os métodos são chamados de, Base Classmas se você substituir, é necessário que você chame o superoutro que você teráandroid.app.SuperNotCalledException
Sunil Mishra
1
Você parece não entender. A questão não é ligar ou não. Como você apontou, você TEM que, se os substituir. A questão é: quando?
Anudeep Bulla
1

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 .

NickT
fonte
O link para a postagem de Dianne Hackborn é importante e confirma o padrão.
Nick Westgate
0

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.

Steve Benett
fonte
A sequência em onCreate parece bastante compreensível. O que acontece nos métodos de destruição? Diga onStop. Suponha que minha implementação onStop use alguns dos recursos que o super método libera se chamado. Faz sentido, então, chamar o super método após minha implementação.
Anudeep Bulla
Idealmente, esse deveria ser o caso, certo. Nossa atividade sempre terá recursos que a superclasse possui, e mais alguns. E os que são independentes da minha atividade podem, na maioria dos casos, depender dos recursos da superclasse, que são comuns. Faz mais sentido lidar primeiro com meus recursos e, em seguida, chamar a superclasse para lidar com os comuns. Por que o Google diz que "DEVEMOS" chamar os métodos da superclasse primeiro?
Anudeep Bulla
De que recurso você está falando, que pode acessar em onCreate, mas não em onDestroy?
Steve Benett,
Eu não tenho um caso de uso. Só estou me perguntando como isso varia com o estilo OOP. Os construtores de superclasse são chamados primeiro, antes de sua implementação, e os destruidores de superclasse são chamados por último, após sua implementação, certo? onPause, onStop e onDestroy não são estritamente destruidores, mas tendem a fazer a mesma coisa, certo? Atleast onDestroy e principalmente onStop também .. não?
Anudeep Bulla de
Veja os retornos de chamada na forma de mudança de estado, não como um construtor / destruidor. Cada retorno de chamada tem sua necessidade, por exemplo, criar (pronto para usar) / destruir (sua última chance de interagir) uma atividade ou colocá-la em primeiro plano / segundo plano. Os callbacks existem para que você possa controlar seus recursos no fluxo do sistema. O sistema apenas verifica em que estado ele está e trata de acordo. Os recursos que você usa e aquele que o sistema controla são independentes um do outro e não haverá interseção.
Steve Benett,