Puisque (vous dites) il est logique d'appeler d'abord super onCreate: pensez-y.
Quand je veux créer, Mon super crée ses ressources> Je crée mes ressources.
Inversement: (sorte de pile)
Quand je veux détruire, je détruis mes ressources> Mon super détruit ses ressources.
En ce sens, il s'applique à n'importe quel couple de fonctions (onCreate / onDestroy, onResume / onPause, onStart / onStop). Naturellement, onCreate créera des ressources et onDestroy libérera ces ressources. D'ailleurs, la même preuve s'applique aux autres couples.
Considérons une bibliothèque que vous avez téléchargée qui a une LocationActivity qui contient une fonction getLocation () qui fournit l'emplacement. Très probablement, cette activité devra initialiser son contenu dans onCreate (), ce qui vous obligera à appeler le super.onCreate en premier. Vous faites déjà cela parce que vous pensez que cela a du sens. Maintenant, dans votre onDestroy, vous décidez que vous souhaitez enregistrer l'emplacement quelque part dans SharedPreferences. Si vous appelez d'abord super.onDestroy, il est dans une certaine mesure possible que getLocation renvoie une valeur nulle après cet appel car l'implémentation de LocationActivity annule la valeur d'emplacement dans onDestroy. L'idée est que vous ne le blâmeriez pas si cela se produit. Par conséquent, vous appelleriez super.onDestroy à la fin une fois que vous en avez terminé avec votre propre onDestroy. J'espère que cela a un peu de sens.
Si ce qui précède a du sens, considérez qu'à tout moment nous avons une activité qui respecte le concept ci-dessus. Si je veux étendre cette activité, je ressentirai probablement la même chose et suivrai le même ordre à cause du même argument exact.
Par induction, toute activité doit faire la même chose. Voici une bonne classe abstraite pour une activité obligée de suivre ces règles:
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);
}
}
Enfin, que se passe-t-il si votre activité appelée AnudeepBullaActivity
étend BaseActivity et plus tard, je souhaite créer une SherifElKhatibActivity
extension de votre activité? Dans quel ordre dois-je appeler les super.do
fonctions? C'est finalement la même chose.
Quant à votre question:
Je pense que l'intention de Google est de nous dire: s'il vous plaît appelez le super, peu importe où. Comme pratique générale, appelez-le au début. Google a bien sûr les ingénieurs et les développeurs les plus brillants, ils ont donc probablement fait du bon travail en isolant leurs super appels et en n'interférant pas dans les appels enfants.
J'ai essayé un peu et ce n'est probablement pas facile (puisque c'est Google que nous essayons de prouver le contraire) de créer une activité qui planterait simplement à cause du super appel de When.
Pourquoi?
Tout ce qui est fait dans ces fonctions est vraiment privé pour la classe Activity et ne provoquerait jamais de conflit avec votre sous-classe. Par exemple (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 et mManagedDialogs et mSearchManager sont tous des champs privés. Et aucune des API publiques / protégées ne sera affectée par ce qui est fait ici.
Cependant, dans l'API 14, dispatchActivityDestroyed a été ajouté pour distribuer un onActivityDestroyed aux ActivityLifecycleCallbacks enregistrés dans votre application. Par conséquent, tout code qui dépendrait d'une logique dans vos ActivityLifecycleCallbacks aura un résultat différent en fonction du moment où vous appelez le super. Par exemple:
Créez une classe d'application qui compte le nombre d'activités en cours d'exécution:
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) {}
}
Ce qui suit peut ne pas avoir de sens ou n'est pas celui d'une bonne pratique, mais c'est juste pour prouver un point (on pourrait trouver une situation plus réelle). Créez la MainActivity qui va supposément à l'activité GoodBye lorsqu'elle est terminée et quand il s'agit de la dernière activité:
@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 vous appelez super.onDestroy au début de votre onDestroy, l'activité GoodBye sera lancée. Si vous appelez super.onDestroy à la fin de votre onDestroy, l'activité GoodBye ne sera pas lancée.
Bien sûr, encore une fois, ce n'est pas l'exemple optimal. Cependant, cela montre que Google a un peu foiré ici. Aucune des autres variables n'aurait affecté le comportement de votre application. Cependant, l'ajout de ces envois à onDestroy a amené le super à interférer d'une manière ou d'une autre avec votre sous-classe.
Je dis qu'ils ont également gâché pour une raison différente. Non seulement ils (avant api 14) n'ont touché que dans les super appels ce qui est final et / ou privé, mais ils ont également appelé différentes fonctions internes (privées) qui ont ensuite vraiment distribué les fonctions onPause ...
Par exemple, performStop
function est la fonction appelée qui à son tour appelle la fonction 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;
}
Notez qu'ils appellent l'activité onStop quelque part dans cette fonction. Par conséquent, ils auraient tout aussi bien pu mettre tout le code (inclus dans super.onStop) avant ou après l'appel à onStop, puis simplement notifier les sous-classes à propos de onStop en utilisant des super fonctions onStop vides et sans même ajouter l'exception SuperNotCalledException ou vérifier cette appelée.
Pour cela, s'ils appelaient cette distribution à ActivityLifeCycle dans performDestroy au lieu de l'appeler à la fin de super.onDestroy, le comportement de notre activité aurait été le même quel que soit le moment où nous avons appelé le super.
Quoi qu'il en soit, c'est la première chose qu'ils font (un peu mal) et ce n'est que dans l'API 14.