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

Estaba pasando por el sitio de desarrolladores de Android, actualizando el ciclo de actividad y en cada ejemplo de código, hay un comentario al lado de los métodos de superclase que dice "Siempre llama al método de superclase primero".

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 ciclo medio de destrucción: onPause, onStop, onDestroy.

Destruir primero los recursos específicos de la instancia, antes de destruir los recursos de superclase de los que dependen los recursos específicos de la instancia, no es lo contrario. Pero los comentarios sugieren lo contrario. ¿Qué me estoy perdiendo?

Edit : Ya que la gente parece estar confundido en cuanto a la intención en la pregunta, lo que quiero saber es que de lo siguiente es correcto? Y POR QUÉ ?

1.Google sugiere

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

2.El otro camino

  @Override protected void onStop() { //my implementation here super.onStop(); } 

Destruir los recursos específicos de la instancia en primer lugar, antes de destruir los recursos de superclase de los que dependen 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: no una sola cosa.

Esta respuesta de Mark (aka CommonsWare en SO) arroja luz sobre el problema: Enlace – ¿Debe la llamada al método de superclase ser la primera declaración? . Pero entonces, usted puede ver el siguiente comentario a la izquierda en su respuesta:

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

Volver al punto de partida. Bueno, veamos esto desde otro ángulo. Sabemos que Java Language Specification no especifica un orden en el que se debe colocar la llamada a super.overridenMethod() (o si la llamada debe ser colocada en absoluto).

En caso de actividad de clase, las llamadas super.overridenMethod() son obligatorias y obligatorias :

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

mCalled se establece en true en Activity.onStop() .

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

I also know that both work

Por supuesto. Mire 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; } 

Sea cual sea la forma en que se super.onPause() la llamada a super.onPause() , usted 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 puede ser importante dependiendo de cómo se configure su actividad, y si llamar a super.onDestroy() podría interferir con el código que sigue.

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

 public class ListActivity extends Activity { .... @Override protected void onDestroy() { mHandler.removeCallbacks(mRequestFocus); super.onDestroy(); } .... } 

Y, de la aplicación de ejemplo de LunarLander incluida en android sdk:

 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 una llamada a super.onPause() debe retrasarse en caso de que una Actividad se inicie con startActivityForResult(Intent) . Ajustar el resultado usando setResult(...) después de 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 últimos se sigue de la lógica:

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 sus cosas en el onCreate () lo que le obligará a llamar primero al super.onCreate . Ya lo haces porque sientes 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 en primer lugar, es hasta cierto punto 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 usted no la culparía si esto sucede. Por lo tanto, usted llamaría super.onDestroy al final después de que haya terminado con su propio onDestroy.

Él continúa super.X() : si una clase de niño está adecuadamente aislada (en términos de dependencia de recursos) de la clase padre, las llamadas super.X() no necesitan cumplir con ninguna especificación de orden.

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

De una respuesta de Mark :

Métodos que reemplazar que son parte de la creación de componentes (onCreate (), onStart (), onResume (), etc), debe encadenar a la superclase como la primera declaración , para asegurarse de que Android tiene su oportunidad de hacer su trabajo antes de que Intentar hacer algo que se basa en que el trabajo que se ha hecho.

Métodos que anulas que son parte de la destrucción de componentes (onPause (), onStop (), onDestroy (), etc.), deberías hacer tu trabajo primero y encadenar a la superclase como la última cosa . De esta forma, en caso de que Android limpie algo de lo que depende su trabajo, habrá hecho su trabajo primero.

Métodos que devuelven algo distinto de void (onCreateOptionsMenu (), etc.), a veces se encadena a la superclase en la instrucción return, suponiendo que no está haciendo específicamente algo que necesite forzar un determinado valor de retorno.

Todo lo demás – como onActivityResult () – depende de usted, en general. Tiendo a encadenar a la superclase como la primera cosa, pero a menos que usted esté funcionando en problemas, encadenamiento más adelante debe ser fino.

Bob Kerns de este hilo :

Es un buen patrón [(el patrón que Mark sugiere arriba)], pero he encontrado algunas excepciones. Por ejemplo, el tema que quería aplicar a mi PreferenceActivity no tendrí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:

Sólo conozco una situación, donde es necesario el momento de la super llamada. Si quieres cambiar el comportamiento estándar del tema o la pantalla y tal en onCreate, tienes que hacerlo antes de llamar a super para ver un efecto . De lo contrario AFAIK no hay diferencia a qué hora lo llaman.

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 de actividad. También afirma que llamar métodos de superclase primero 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 anterior a todo lo demás. En mi opinión, esta explicación no agrega a la pregunta que se hace.

Nota final : Confíe, pero verifique. La mayoría de las respuestas de esta página siguen este enfoque para ver si la instrucción Always call the superclass method first tiene respaldo lógico. Como resulta, no lo hace; 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 llamadas a los métodos super es un requisito.

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

Cuando quiero crear, My super crea sus recursos> Creo mis recursos.

Inversamente: (tipo 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 liberará estos recursos. 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 sus cosas en el onCreate () lo que le obligará a llamar primero al super.onCreate. Ya lo haces porque sientes 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 en primer lugar, es hasta cierto punto 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 usted no la culparía si esto sucede. Por lo tanto, usted 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 respeta el concepto anterior. Si quiero extender esta actividad, probablemente me sentiré de la misma manera y seguiré el mismo orden debido al mismo argumento exacto.

Por inducción, cualquier actividad debe hacer lo mismo. Esta es 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é AnudeepBullaActivity si su actividad llamada AnudeepBullaActivity extiende BaseActivity y más adelante, quiero crear SherifElKhatibActivity que amplíe su actividad? ¿En qué orden debo llamar a las funciones super.do ? En última instancia, es la misma cosa.


En cuanto a su pregunta:

Creo que la intención de Google es decirnos: Por favor llame a la super no importa dónde. Como una práctica general, por supuesto, llámelo al principio. Google, por supuesto, tiene los ingenieros más brillantes y los desarrolladores por lo que probablemente hizo un buen trabajo aislar sus súper llamadas y no interferir en las llamadas de niño.

He intentado un poco y probablemente no es fácil (ya que es Google estamos tratando de demostrar que es incorrecto) para crear una actividad que se bloquea simple, porque de cuándo es super ser llamado.

¿Por qué?

Cualquier cosa que se haga en estas funciones es realmente privada para la clase de actividad 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 campos privados. Y ninguno de los api público / protegido se verá afectado por lo que se hace aquí.

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

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

 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 el de una buena práctica, pero es sólo para demostrar un punto (Uno podría encontrar una situación más real). Cree la MainActivity que supuestamente va a la actividad de GoodBye cuando se termina 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 principio de su onDestroy, se iniciará la actividad GoodBye. Si llama a super.onDestroy al final de su onDestroy, la actividad GoodBye no se iniciará.

Por supuesto, de nuevo, este no es el ejemplo óptimo. Sin embargo, esto muestra que Google se perdió un poco aquí. Cualquiera de las otras variables no habría afectado el comportamiento de su aplicación. Sin embargo agregando estos despachos a la onDestroy causado el super de alguna manera interferir con su subclase.

Yo digo que metieron por una razón diferente también. No sólo (sólo api 14) tocan en las súper llamadas lo que es final y / o privado, sino que también llaman a diferentes funciones internas (privadas) que realmente despachan las funciones onPause ….

Por ejemplo, la función performStop 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 onStop de la Actividad en algún lugar de esta función. Por lo tanto, es posible que también haya puesto todo el código (incluido en super.onStop) antes o después de la llamada a onStop y luego simplemente notifique subclases sobre el onStop utilizando funciones super super onStop vacías y sin siquiera agregar SuperNotCalledException o comprobando para esto llamado.

Para esto, si llamaron a este envío a ActivityLifeCycle en el performDestroy en lugar de llamar al final de super.onDestroy, el comportamiento de nuestra actividad habría sido el mismo independientemente de cuando llamamos a la super.

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

Lo más importante a tener en cuenta es que super.onPause() implícitamente llama a setResult(Activity.RESULT_CANCELED) . Pero setResult sólo se puede llamar una vez, y todas las llamadas posteriores se ignoran. Así que si quieres empujar cualquier tipo de resultado de vuelta a la actividad padre, tienes que llamar a setResult tú mismo, antes de llamar a super.onPause() . Eso es lo más grande que tengo, por lo que sé.

AMBOS son correctos IMO

Según los documentos

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

Super método Super siempre debe ser llamado cuando la documentación lo dice explícitamente.

Sin embargo, puede elegir cuándo llamar al método super.

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 llama. Deberías ser bueno.

Pero para la mejor práctica, deberías llamarla primero.

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

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

Usted dice que Google sugiere el método 1, sin embargo Dianne Hackborn, un conocido ingeniero de framework de Android sugieren lo contrario ver Google Forum Link .

Hace sentido intuitivo llamar a la clase súper última cuando destruye una instancia en los métodos onPause, onStop y onDestroy y primero al crear una instancia con los métodos de onCreate, onResume y onStart .

El súper de las devoluciones de llamada es necesario para poner la Actividad en el estado correcto internamente para el sistema.

Digamos que inicie su Actividad y onCreate es invocado por el sistema. Ahora puede anularlo y, por ejemplo, cargar su diseño. Pero en aras del flujo del sistema tienes que llamar super, que el sistema puede continuar con el procedimiento estándar. Es por eso que se lanzará una excepción si no la llamas.

Esto sucede independientemente de su implementación en onCreate. Es sólo importend para el sistema. Si no hubiera ANR usted podría tener un bucle sin fin en cualquier llamada de retorno y la actividad sería atrapado en ese. Por lo tanto, el sistema sabe cuándo se ha terminado la devolución de llamada y que llama a la siguiente.

Sólo conozco una situación, donde es necesario el momento de la super llamada. Si quieres cambiar el comportamiento estándar del tema o la pantalla y tal en onCreate, tienes que hacerlo antes de llamar a super para ver un efecto. De lo contrario AFAIK no hay diferencia a qué hora lo llaman.

Pero para dejar que el sistema haga lo que mejor puede poner el super en la primera línea de una devolución de llamada seguido de su código, si usted no tiene una buena razón para romper con ella.

Desde la perspectiva de java aquí hay alguna solución para esta confusión:

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

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

Lo que estás tratando de hacer, pasar args al super constructor es perfectamente legal, solo necesitas construir esos args en línea como lo estás haciendo, o pasarlos a tu constructor y luego pasarlos a super:

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

Si el compilador no hizo cumplir esto, podría hacer esto:

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

¡Demuestra que en realidad, los subcampos tienen que ser inilializados antes de la supreclass! Mientras tanto, el requisito de java "nos defiende" de la especialización de la clase por la especialización de lo que el argumento super constructor

En los casos en que una clase padre tiene un constructor por defecto la llamada a super se inserta automáticamente para usted por el compilador. Como cada clase en Java hereda de Object, el constructor de objetos debe ser llamado de alguna manera y debe ser ejecutado primero. La inserción automática de super () por el compilador lo permite. Haciendo que super aparezca primero, hace cumplir que los cuerpos del constructor se ejecuten en el orden correcto que sería: Objeto -> Parent -> Child -> ChildOfChild -> SoOnSoForth

(1) Comprobar que super es la primera declaración no es suficiente para prevenir 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 instrucción.

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

Por favor, revise esta http://valjok.blogspot.in/2012/09/super-constructor-must-be-first.html

  • WakefulBroadcastReceiver no se puede resolver con un tipo
  • Rendimiento de Scala para Android
  • Obtener el idioma del teclado o detectar el idioma de entrada del usuario en Android
  • ¿Cómo puedo clasificar mi Arraylist alfabético? (Java)
  • Métodos estáticos o Singletons rendimiento-sabio (Android)?
  • ¿Cómo hago que mi ImageView tenga un tamaño fijo independientemente del tamaño del mapa de bits
  • ¿Cómo comparar dos arraylist?
  • No se pudo cargar (encontrar) la biblioteca j2v8_android_x86
  • OutOfMemoryError: Al recibir una respuesta XML de 2.3 MB
  • ¿Cómo implementar un gesto de deslizamiento entre fragmentos?
  • ¿Cómo comprobar los indicadores de gravedad en una vista Android personalizada?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.