¿Cuál es el orden correcto para llamar a los métodos de superclase en los métodos onPause, onStop y onDestroy? ¿y por qué?

89

Estaba revisando el sitio para desarrolladores de Android, actualizando el ciclo de vida de la actividad, y en cada ejemplo de código, hay un comentario al lado de los métodos de superclase que dice "Llamar siempre primero al método de superclase".

Aunque esto tiene sentido en el medio ciclo de creación: onCreate, onStart y onResume, estoy un poco confundido en cuanto a cuál es el procedimiento correcto en el medio ciclo de destrucción: onPause, onStop, onDestroy.

Destruir los recursos específicos de la instancia primero, antes de destruir los recursos de superclase de los que pueden depender los recursos específicos de la instancia, tiene sentido, no al revés, pero los comentarios sugieren lo contrario. ¿Qué me estoy perdiendo?

Editar : Dado que la gente parece confundirse en cuanto a la intención de la pregunta, lo que quiero saber es cuál de las siguientes opciones es correcta. Y POR QUÉ ?

1.Google sugiere

    @Override
    protected void onStop() {
      super.onStop();  // Always call the superclass method first

      //my implementation here
    }

2 al revés

    @Override
    protected void onStop() {
       //my implementation here

       super.onStop();  
    }
Anudeep Bulla
fuente
1
Estoy en el campo dos por los métodos de cierre. Estoy en el campo uno para los métodos de inicio.
danny117
1
Ese es básicamente el punto. Simplemente no podía entender cómo tenía sentido usar el método 1 para los métodos de apagado.
Anudeep Bulla

Respuestas:

107

Destruir primero los recursos específicos de la instancia, antes de destruir los recursos de superclase de los que pueden depender los recursos específicos de la instancia, tiene sentido, no al revés. Pero los comentarios sugieren lo contrario. ¿Qué me estoy perdiendo?

En mi opinión: ni una sola cosa.

Esta respuesta de Mark (también conocido como CommonsWare en SO) arroja luz sobre el problema: Enlace: ¿La llamada al método de superclase debería ser la primera declaración? . Pero luego, puede ver el siguiente comentario dejado en su respuesta:

Pero, ¿por qué el documento oficial dice: "Llame siempre primero al método de superclase" en onPause ()?

Volver al punto de partida. Bien, veamos esto desde otro ángulo. Sabemos que la Especificación del lenguaje Java no especifica un orden en el que se super.overridenMethod()debe realizar la llamada a (o si se debe realizar la llamada).

En el caso de la actividad de la clase, super.overridenMethod()se requieren y se hacen cumplir las llamadas :

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

mCalledse establece en verdadero en Activity.onStop().

Ahora, el único detalle que queda por debatir es el ordenamiento.

I also know that both work

Por supuesto. Mira el cuerpo del 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;
}

Independientemente de la forma en que intervenga la llamada super.onPause(), estará bien. Activity.onStop () tiene un cuerpo de método similar. Pero eche un vistazo a 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);
}

Aquí, el orden podría ser importante dependiendo de cómo esté configurada su actividad y si la llamada super.onDestroy()interferiría con el código que sigue.

Como palabra final, la declaración Always call the superclass method firstno parece tener mucha evidencia que la respalde. Lo que es peor (para la declaración) es que se ha tomado el siguiente código de android.app.ListActivity:

public class ListActivity extends Activity {

    ....

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

Y, de la aplicación de muestra LunarLander incluida en el SDK de Android:

public class LunarLander extends Activity {

    ....

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

Resumen y menciones dignas:

Usuario Philip Sheard : proporciona un escenario en el que se super.onPause()debe retrasar una llamada a en caso de que se inicie el uso de una actividad startActivityForResult(Intent). Configurar el resultado usando setResult(...) after super.onPause() no funcionará. Más tarde aclara esto en los comentarios a su respuesta.

Usuario Sherif elKhatib : explica por qué dejar que la superclase inicialice sus recursos primero y destruya sus recursos en último lugar sigue la lógica:

Consideremos una biblioteca que descargó que tiene LocationActivity que contiene una función getLocation () que proporciona la ubicación. Lo más probable es que esta actividad deba inicializar su contenido en onCreate (), lo que te obligará a llamar primero a super.onCreate . Ya lo hace porque siente que tiene sentido. Ahora, en su onDestroy, decide que desea guardar la Ubicación en algún lugar de SharedPreferences. Si llama a super.onDestroy primero, hasta cierto punto es posible que getLocation devuelva un valor nulo después de esta llamada porque la implementación de LocationActivity anula el valor de ubicación en onDestroy. La idea es que no lo culparías si esto sucediera.Por lo tanto, llamaría super.onDestroy al final después de que haya terminado con su propio onDestroy.

Continúa señalando: si una clase secundaria está adecuadamente aislada (en términos de dependencia de recursos) de la clase principal, las super.X()llamadas no necesitan adherirse a ninguna especificación de orden.

Ver su respuesta en esta página para leer a través de un escenario en el que la colocación de la super.onDestroy()llamada no afecta a la lógica del programa.

De una respuesta de Mark :

Los métodos que anula que son parte de la creación de componentes (onCreate (), onStart (), onResume (), etc.), debe encadenar a la superclase como primera declaración , para asegurarse de que Android tenga la oportunidad de hacer su trabajo antes intente hacer algo que dependa de que ese trabajo se haya realizado.

Los métodos que anula y que forman parte de la destrucción de componentes (onPause (), onStop (), onDestroy (), etc.), debe hacer su trabajo primero y encadenar a la superclase como último paso . De esa manera, en caso de que Android limpie algo de lo que depende tu trabajo, habrás hecho tu trabajo primero.

Los métodos que devuelven algo que no sea void (onCreateOptionsMenu (), etc.), a veces se encadenan a la superclase en la declaración de retorno, asumiendo que no está haciendo algo específicamente que necesite forzar un valor de retorno particular.

Todo lo demás, como onActivityResult (), depende de usted, en general. Tiendo a encadenarme a la superclase como lo primero, pero a menos que tenga problemas, encadenar más tarde debería estar bien.

Bob Kerns de este hilo :

Es un buen patrón [(el patrón que sugiere Mark arriba)], pero he encontrado algunas excepciones. Por ejemplo, el tema que quería aplicar a mi PreferenceActivity no surtiría efecto a menos que lo ponga antes de onCreate () de la superclase.

El usuario Steve Benett también llama la atención sobre esto:

Solo conozco una situación en la que es necesario el tiempo de la súper llamada. Si desea modificar el comportamiento estándar del tema o la pantalla y demás en onCreate, debe hacerlo antes de llamar a super para ver un efecto . De lo contrario, AFAIK, no hay diferencia en el momento en que lo llame.

El usuario Sunil Mishra confirma que el orden (lo más probable) no juega un papel al llamar a los métodos de la clase Activity. También afirma que llamar primero a los métodos de superclase se considera una mejor práctica . Sin embargo, no pude corroborar esto.

Usuario LOG_TAG : explica por qué una llamada al constructor de superclase debe ser antes que todo lo demás. En mi opinión, esta explicación no se suma a la pregunta que se hace.

Nota final : confíe, pero verifique. La mayoría de las respuestas en esta página siguen este enfoque para ver si la declaración Always call the superclass method firsttiene un respaldo lógico. Resulta que no es así; al menos, no en el caso de la actividad de clase. Generalmente, uno debe leer el código fuente de la superclase para determinar si ordenar las llamadas a los métodos de super es un requisito.

Vikram
fuente
2
Guau. Gracias por los consejos. Tanto esta como las respuestas de @ Sherif proporcionan un contexto importante. Si alguno de ustedes puede resumir las respuestas en esta página, lo marcaría como aceptado. Por favor incluya: 1.Respuestas en esta página. 2. La respuesta de @ Philip en esta página 3. La respuesta de @ CommonsWare en esta página 4. Esta discusión lo haría, pero no quiero los créditos por sus maravillosas respuestas. Saludos y gracias
Anudeep Bulla
Hola. ¿Podrías resumir, ya que @Sherif no quiere?
Anudeep Bulla
@AnudeepBulla Hola Anudeep, dame hasta mañana. Agregaré el material relevante a mi respuesta y te dejaré un comentario aquí.
Vikram
@AnudeepBulla He agregado un resumen arriba. Por favor, avíseme en caso de que me haya perdido algo.
Vikram
@Vikram es el TL; DR. que llamar onDestroyy onStopúltimo es un valor predeterminado más seguro, y que las onPausecosas pueden ser más complicadas en algunos casos? ¿Podría agregar eso primero? Tuve la tentación de editar la respuesta yo mismo, pero no estoy seguro de que este resumen sea correcto.
Blaisorblade
13

Ya que (dices) tiene sentido llamar a super onCreate primero: Piénsalo.

Cuando quiero crear, Mi super crea sus recursos> Yo creo mis recursos.

Inversamente: (una especie de pila)

Cuando quiero destruir, destruyo mis recursos> Mi súper destruye sus recursos.


En este sentido, se aplica a cualquier par de funciones (onCreate / onDestroy, onResume / onPause, onStart / onStop). Naturalmente, onCreate creará recursos y onDestroy los liberará. Por cierto, la misma prueba se aplica a las otras parejas.

Consideremos una biblioteca que descargó que tiene una LocationActivity que contiene una función getLocation () que proporciona la ubicación. Lo más probable es que esta actividad necesite inicializar su contenido en onCreate (), lo que te obligará a llamar primero a super.onCreate. Ya lo hace porque siente que tiene sentido. Ahora, en su onDestroy, decide que desea guardar la Ubicación en algún lugar de SharedPreferences. Si llama a super.onDestroy primero, hasta cierto punto es posible que getLocation devuelva un valor nulo después de esta llamada porque la implementación de LocationActivity anula el valor de ubicación en onDestroy. La idea es que no lo culparías si esto sucediera. Por lo tanto, llamaría super.onDestroy al final después de que haya terminado con su propio onDestroy. Espero que esto tenga un poco de sentido.

Si lo anterior tiene sentido, considere que en cualquier momento tenemos una actividad que se apega al concepto anterior. Si quiero extender esta actividad, probablemente sentiré lo mismo y seguiré el mismo orden debido al mismo argumento exacto.

Por inducción, cualquier actividad debería hacer lo mismo. Aquí hay una buena clase abstracta para una actividad obligada a seguir estas reglas:

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, ¿qué AnudeepBullaActivitypasa si tu actividad llamada extiende BaseActivity y luego quiero crear SherifElKhatibActivityque amplíe tu actividad? ¿En qué orden debo llamar a las super.dofunciones? En última instancia, es lo mismo.


En cuanto a tu pregunta:

Creo que la intención de Google es decirnos: por favor, llame al superintendente sin importar dónde. Como práctica general, por supuesto, llámelo al principio. Google, por supuesto, tiene los ingenieros y desarrolladores más brillantes, por lo que probablemente hicieron un buen trabajo al aislar sus super llamadas y no interferir en las llamadas de los niños.

Intenté un poco y probablemente no sea fácil (ya que es Google lo que estamos tratando de demostrar que estamos equivocados) crear una actividad que se bloquee de manera simple debido a la llamada de When is super.

¿Por qué?

Todo lo que se haga en estas funciones es realmente privado para la clase Activity y nunca causaría ningún conflicto con su subclase. Por ejemplo (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 y mManagedDialogs y mSearchManager son todos campos privados. Y ninguna de las API públicas / protegidas se verá afectada por lo que se haga aquí.

Sin embargo, en la API 14, dispatchActivityDestroyed se agregó para enviar un onActivityDestroyed a ActivityLifecycleCallbacks registrados en su aplicación. Por lo tanto, cualquier código que dependa de alguna lógica en su ActivityLifecycleCallbacks tendrá un resultado diferente en función de cuándo llame al super. Por ejemplo:

Cree una clase de aplicación que cuente el número de actividades en ejecución actualmente:

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) {}
}

Lo siguiente puede no tener sentido o no es una buena práctica, pero es solo para probar un punto (uno podría encontrar una situación más real). Cree la MainActivity que supuestamente va a la actividad GoodBye cuando finaliza y cuando es la última actividad:

@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));
    }
}

Si llama a super.onDestroy al comienzo de su onDestroy, se iniciará la actividad Adiós. Si llama a super.onDestroy al final de su onDestroy, la actividad Adiós no se iniciará.

Por supuesto, nuevamente, este no es el ejemplo óptimo. Sin embargo, esto muestra que Google se equivocó un poco aquí. Cualquiera de las otras variables no habría afectado el comportamiento de su aplicación. Sin embargo, agregar estos envíos a onDestroy causó que el súper interfiriera de alguna manera con su subclase.

Yo digo que también se metieron por una razón diferente. No solo (antes de la API 14) solo tocaron en las super llamadas lo que es final y / o privado, sino que también llamaron a diferentes funciones internas (privadas) que realmente luego enviaron las funciones onPause ...

Por ejemplo, performStopfunction es la función llamada que a su vez llama a la función 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 llaman a la actividad onStop en algún lugar de esta función. Por lo tanto, también podrían haber puesto todo el código (incluido en super.onStop) antes o después de la llamada a onStop y luego simplemente notificar a las subclases sobre el onStop usando superfunciones onStop vacías y sin siquiera agregar SuperNotCalledException o verificar esta llamada.

Por esto, si llamaron a este envío a ActivityLifeCycle en performDestroy en lugar de llamarlo al final de super.onDestroy, el comportamiento de nuestra actividad habría sido el mismo independientemente de cuándo llamamos al super.

De todos modos esto es lo primero que hacen (un poco mal) y es solo en API 14.

Sherif elKhatib
fuente
La pregunta nunca ha sido por qué llamar al último super.onDestroy () tiene sentido. Amo tu ejemplo de biblioteca. Exactamente lo que quería transmitir también. No podría estar más de acuerdo en llamar a los súper métodos al final de los semiciclos de destrucción al final, exactamente como en una pila; para evitar la pérdida accidental de datos. El problema es ¿por qué Google insiste en llamar a los súper métodos primero, dada la premisa anterior? Hice la pregunta porque pensé que tal vez yo, y aparentemente tú también, quizás lo aborde de manera completamente diferente. Saludos
Anudeep Bulla
Oh, no vi las sugerencias de Google y de otra manera: p! Escucha, intentaré crear una actividad que se bloqueará si llamas primero a Destroy. Deberías intentarlo también. Saludos
Sherif elKhatib
@AnudeepBulla puedes comprobar mis ediciones. Y por cierto, puedes dejar de intentarlo. super.onprobablemente nunca bloqueará su actividad.
Sherif elKhatib
Guau. Gracias por los consejos. Tanto esta como las respuestas de @ User proporcionan un contexto importante. Si alguno de ustedes puede resumir las respuestas en esta página, lo marcaría como aceptado. Por favor incluya: 1.Respuestas en esta página. 2. La respuesta de @ Philip en esta página 3. La respuesta de @ CommonsWare en esta página 4. Esta discusión lo haría, pero no quiero los créditos por sus maravillosas respuestas. Saludos y gracias
Anudeep Bulla
@AnudeepBulla De nada. No estoy seguro de cómo vamos a decidir quién publica el artículo final.
Vikram
2

Usted dice que Google sugiere el método 1, sin embargo, Dianne Hackborn, un conocido ingeniero de marcos de Android, sugiere lo contrario, consulte el enlace del foro de Google .

Tiene sentido intuitivo llamar a la superclase en último lugar cuando se destruye una instancia en los métodos onPause, onStop y onDestroy y primero cuando se crea una instancia con los métodos de onCreate, onResume y onStart .

NickT
fuente
El enlace a la publicación de Dianne Hackborn es importante y confirma el patrón.
Nick Westgate
1

Desde la perspectiva de Java, aquí hay una solución para esta confusión:

¿Por qué esta () y super () tienen que ser la primera declaración en un constructor?

El constructor de la clase principal debe llamarse antes que el constructor de la subclase. Esto asegurará que si llama a cualquier método en la clase principal en su constructor, la clase principal ya se ha configurado correctamente.

Lo que está tratando de hacer, pasar argumentos al superconstructor es perfectamente legal, solo necesita construir esos argumentos en línea mientras lo está haciendo, o pasarlos a su constructor y luego pasarlos a super:

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

Si el compilador no hizo cumplir esto, puede hacer esto:

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

¡Muestra que, en realidad, los subcampos deben inicializarse antes que la clase suprema! Mientras tanto, el requisito de Java "nos defiende" de especializar la clase al especializar lo que el argumento del superconstructor

En los casos en los que una clase padre tiene un constructor predeterminado, el compilador inserta automáticamente la llamada a super. Dado que cada clase en Java hereda de Object, el constructor de objetos debe llamarse de alguna manera y debe ejecutarse primero. La inserción automática de super () por parte del compilador lo permite. Al hacer que super aparezca primero, obliga a que los cuerpos del constructor se ejecuten en el orden correcto, que sería: Objeto -> Padre -> Niño -> Niño de niño -> SoOnSoForth

(1) Comprobar que super es la primera afirmación no es suficiente para evitar ese problema. Por ejemplo, podría poner "super (someMethodInSuper ());" en su constructor. Esto intenta acceder a un método en la superclase antes de que se construya, aunque super es la primera declaración.

(2) El compilador parece implementar una verificación diferente que, por sí sola, es suficiente para evitar este problema. El mensaje es "no se puede hacer referencia a xxx antes de que se haya llamado al constructor de supertipo". Por lo tanto, no es necesario verificar que super es la primera declaración.

Consulte este http://valjok.blogspot.in/2012/09/super-constructor-must-be-first.html

LOG_TAG
fuente
Entiendo perfectamente lo que estás diciendo. Primero llama a los constructores de superclase, porque pueden inicializar los recursos que el niño puede necesitar; y los destructores duran, porque probablemente no quieras borrar a todos los padres de los recursos locales, haciéndolos inútiles. Ese es mi punto exactamente. Y dado que onPause, onStop y onDestroy tienen el trabajo de guardar información de estado y más o menos hacer que los recursos estén disponibles para GC (por lo que, en cierto sentido, los destruyen), los veo análogos a los destructores y, por lo tanto, creo que llamarlos al final tiene sentido. ¿No?
Anudeep Bulla
Todo lo que dijiste anteriormente es exactamente lo que quise decir cuando dije "llamar primero a los súper métodos tiene sentido en el medio ciclo de creación". Estoy preocupado y confundido en el caso de los métodos de medio ciclo de destrucción, que parecen más análogos a los destructores. Saludos
Anudeep Bulla
1

Lo más importante a tener en cuenta es que super.onPause()llama implícitamente setResult(Activity.RESULT_CANCELED). Pero setResultsolo se puede llamar una vez y todas las llamadas posteriores se ignoran. Entonces, si desea enviar cualquier tipo de resultado a la actividad de los padres, debe llamarse a setResultsí mismo antes de llamar super.onPause(). Ese es el mayor problema, hasta donde yo sé.

Philip Sheard
fuente
Vaya, esto parece importante. Entonces, hay una situación en la que definitivamente tienes que retrasar la llamada a los súper métodos. Gracias.
Anudeep Bulla
super.onPause() implicitly calls setResult(Activity.RESULT_CANCELED). ¿Podrías decir de dónde sacaste esto?
Vikram
Estaba confundido. En realidad, es finish () el que llama a setResult, y super.onBackPressed () llama a finish (). Por lo tanto, definitivamente se debe llamar a setResult antes de super.onBackPressed (). No estoy seguro de si hay alguna circunstancia en la que super.onPause () pueda hacer que se llame a setResult, pero prefiero no arriesgarme.
Philip Sheard
1

AMBOS son correctos en mi opinión

Según los documentos

Las clases derivadas deben llamar a la implementación de este método por parte de la superclase. Si no lo hacen, se lanzará una excepción.

Super Siempre se debe llamar al método cuando la documentación lo indique explícitamente.

Sin embargo, puede elegir cuándo llamar al súper método.

Mirando la fuente de onPause

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

Por lo tanto, no importa antes o después de que se llame. Deberías estar bien.

Pero como mejor práctica, debería llamarlo primero.

Lo recomiendo principalmente como mecanismo de protección: si hay una excepción, entonces el super método de instancia ya habrá sido llamado.

Además, poner estas llamadas en la primera línea le ayudará a evitar cometer errores en el futuro, como eliminar código en el método y eliminar accidentalmente la llamada a la superclase.

Sunil Mishra
fuente
Lo siento si la pregunta no fue del todo clara la primera vez, pero por favor échale un vistazo ahora.
Anudeep Bulla
@AnudeepBulla Eso es lo que te he explicado. Puede utilizar cualquiera de ellos. Ambos son válidos.
Sunil Mishra
Tengo entendido que la implementación personalizada de los métodos onPause, onStop y onDestroy no es estrictamente necesaria. He creado amplias aplicaciones sin esas. Entonces, ¿a qué te refieres con los Super métodos que siempre deben llamarse? Se llaman implícitamente, incluso sin anular. También sé que ambos funcionan. Quiero saber por qué los doctores dicen que se debería llamar a Super primero. Y en caso de que la pregunta aún no sea evidente, ¿podría explicar POR QUÉ, cuando diga "Pero como mejor práctica, debería llamarlo primero"?
Anudeep Bulla
Si no anula, los métodos se llaman desde, Base Classpero si anula, es necesario que llame al superotro que tendráandroid.app.SuperNotCalledException
Sunil Mishra
1
Pareces malinterpretar. La cuestión no es si llamar o no. Como señaló, TIENE que hacerlo, si las anula. La pregunta es, ¿cuándo?
Anudeep Bulla
0

El super de las devoluciones de llamada es necesario para poner la actividad en el estado correcto internamente para el sistema.

Digamos que inicias tu actividad y el sistema invoca onCreate. Ahora puede anularlo y, por ejemplo, cargar su diseño. Pero en aras del flujo del sistema, debe llamar a super, para que el sistema pueda continuar con el procedimiento estándar. Es por eso que se lanzará una excepción si no la llama.

Esto sucede independientemente de su implementación en onCreate. Solo es importante para el sistema. Si no hubiera ANR, podría tener un bucle sin fin en cualquier devolución de llamada y la Actividad quedaría atrapada en ese. Entonces, el sistema sabe cuándo se ha terminado la devolución de llamada y luego llama a la siguiente.

Solo conozco una situación, en la que el tiempo de la súper llamada es necesario. Si desea modificar el comportamiento estándar del tema o la pantalla y demás en onCreate, debe hacerlo antes de llamar a super para ver un efecto. De lo contrario, AFAIK, no hay diferencia en el momento en que lo llame.

Pero para dejar que el sistema haga lo que mejor pueda, coloque el super en la primera línea de una devolución de llamada seguida de su código, si no tiene una buena razón para romper con él.

Steve Benett
fuente
La secuencia en onCreate parece bastante comprensible. ¿Qué pasa con los métodos de destrucción? Di onStop. Supongamos que mi implementación onStop usa algunos de los recursos que libera el súper método si se llama. Tiene sentido entonces, llamar al súper método después de mi implementación.
Anudeep Bulla
Idealmente, este debería ser el caso, ¿verdad? Nuestra actividad siempre tendrá recursos que tiene la superclase, y algunos más, y los que son independientes de mi actividad pueden, en la mayoría de los casos, depender de los recursos de la superclase, que son comunes. Tiene más sentido ocuparse primero de mis recursos y luego llamar a la superclase para que se ocupe de los comunes. ¿Por qué Google dice que "DEBEMOS" llamar a los métodos de superclase primero?
Anudeep Bulla
¿De qué recurso estás hablando, al que puedes acceder en onCreate pero no en onDestroy?
Steve Benett
No tengo un caso de uso. Me pregunto cómo varía con el estilo de programación orientada a objetos. Los constructores de súper clases se llaman primero, antes de su implementación, y los destructores de súper clases se llaman en último lugar, después de su implementación, ¿verdad? onPause, onStop y onDestroy no son estrictamente destructores, pero tienden a hacer lo mismo, ¿verdad? Al menos onDestroy y sobre todo onStop también ... ¿no?
Anudeep Bulla
Vea las devoluciones de llamada en la forma de cambio de estado, no como un constructor / destructor. Cada devolución de llamada tiene su necesidad, por ejemplo, crear (lista para usar) / destruir (su última oportunidad de interactuar) una Actividad o ponerla en primer plano / fondo. Las devoluciones de llamada están ahí para que pueda controlar sus recursos en el flujo del sistema. El sistema simplemente verifica en qué estado se encuentra y lo maneja en consecuencia. Los recursos que utiliza y el que controla el sistema son independientes entre sí y no habrá intersecciones.
Steve Benett