J'étais en train de parcourir le site des développeurs Android, actualisant le cycle de vie des activités, et dans chaque exemple de code, il y a un commentaire à côté des méthodes de super classe qui dit "Appelez toujours la méthode de superclasse en premier".
Bien que cela ait du sens dans le demi-cycle de création: onCreate, onStart et onResume, je ne sais pas trop quelle est la procédure correcte sur le demi-cycle de destruction: onPause, onStop, onDestroy.
Il est logique de détruire d'abord les ressources spécifiques à l'instance, avant de détruire les ressources de la superclasse dont les ressources spécifiques à l'instance peuvent dépendre, et non l'inverse, mais les commentaires suggèrent le contraire. Qu'est-ce que je rate?
Edit : Puisque les gens semblent être confus quant à l'intention de la question, ce que je veux savoir, c'est lequel des éléments suivants est correct? ET POURQUOI ?
1.Google suggère
@Override
protected void onStop() {
super.onStop(); // Always call the superclass method first
//my implementation here
}
2. l'autre manière
@Override
protected void onStop() {
//my implementation here
super.onStop();
}
la source
Réponses:
A mon avis: pas une seule chose.
Cette réponse de Mark (alias CommonsWare on SO) met en lumière le problème: Lien - L'appel à la méthode superclasse devrait-il être la première déclaration? . Mais alors, vous pouvez voir le commentaire suivant laissé sur sa réponse:
Retour à la case départ. D'accord, regardons cela sous un autre angle. Nous savons que la spécification du langage Java ne spécifie un ordre dans lequel l'appel à
super.overridenMethod()
doit être placé (ou si l'appel doit être passé du tout).En cas d'activité de classe, les
super.overridenMethod()
appels sont obligatoires et appliqués :mCalled
est défini sur true dansActivity.onStop()
.Maintenant, le seul détail qui reste à débattre est la commande.
I also know that both work
Sûr. Regardez le corps de la méthode pour Activity.onPause ():
Quelle que soit la façon dont vous prenez l'appel
super.onPause()
, tout ira bien. Activity.onStop () a un corps de méthode similaire. Mais jetez un œil à Activity.onDestroy ():Ici, la commande pourrait éventuellement importance en fonction de la configuration de votre activité et du fait que l'appel
super.onDestroy()
interférerait avec le code qui suit.En guise de dernier mot, la déclaration
Always call the superclass method first
ne semble pas avoir beaucoup de preuves pour l'étayer. Ce qui est pire (pour l'instruction), c'est que le code suivant a été extrait deandroid.app.ListActivity
:Et, à partir de l'exemple d'application LunarLander inclus dans Android SDK:
Résumé et mentions dignes:
Utilisateur Philip Sheard : fournit un scénario dans lequel un appel à
super.onPause()
doit être retardé en cas de démarrage d'une activitéstartActivityForResult(Intent)
. La définition du résultat en utilisantsetResult(...)
aftersuper.onPause()
ne fonctionnera pas. Il clarifie plus tard ce point dans les commentaires à sa réponse.Utilisateur Sherif elKhatib : explique pourquoi laisser la superclasse initialiser ses ressources en premier et détruire ses ressources en dernier découle de la logique:
Il poursuit en soulignant: si une classe enfant est convenablement isolée (en termes de dépendance de ressources) de la classe parente, les
super.X()
appels ne doivent adhérer à aucune spécification d'ordre.Voir sa réponse sur cette page pour lire un scénario où le placement d'
super.onDestroy()
appel n'affecte la logique du programme.D'après une réponse de Mark :
Bob Kerns de ce fil :
L'utilisateur Steve Benett attire également l'attention sur ceci:
L'utilisateur Sunil Mishra confirme que l'ordre (très probablement) ne joue pas de rôle lors de l'appel des méthodes de la classe Activity. Il affirme également qu'appeler d'abord les méthodes de superclasse est considéré comme une meilleure pratique . Cependant, je ne pouvais pas le corroborer.
Utilisateur LOG_TAG : explique pourquoi un appel au constructeur de superclasse doit être avant tout le reste. À mon avis, cette explication n'ajoute rien à la question posée.
Note de fin : Faites confiance, mais vérifiez. La plupart des réponses sur cette page suivent cette approche pour voir si l'instruction
Always call the superclass method first
a un soutien logique. En fait, ce n'est pas le cas; du moins, pas dans le cas de l'activité de classe. Généralement, il faut lire le code source de la superclasse pour déterminer si l'ordre des appels aux méthodes de super est une exigence.la source
onDestroy
etonStop
durer est un défaut plus sûr, et que pour lesonPause
choses peuvent être plus délicates dans quelques cas? Pourriez-vous ajouter cela en premier? J'ai été tenté de modifier la réponse moi-même mais je ne suis pas sûr que ce résumé soit correct.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:
Enfin, que se passe-t-il si votre activité appelée
AnudeepBullaActivity
étend BaseActivity et plus tard, je souhaite créer uneSherifElKhatibActivity
extension de votre activité? Dans quel ordre dois-je appeler lessuper.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)
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:
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é:
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: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.
la source
super.on
ne plantera probablement jamais votre activité.Du point de vue de Java, voici une solution à cette confusion:
Pourquoi this () et super () doivent-ils être la première instruction d'un constructeur?
Le constructeur de la classe parente doit être appelé avant le constructeur de la sous-classe. Cela garantira que si vous appelez des méthodes sur la classe parente dans votre constructeur, la classe parente a déjà été configurée correctement.
Ce que vous essayez de faire, passer des arguments au super constructeur est parfaitement légal, il vous suffit de construire ces arguments en ligne comme vous le faites, ou de les transmettre à votre constructeur puis de les transmettre à super:
Si le compilateur n'a pas appliqué cela, vous pouvez le faire:
Cela montre qu'en fait, les sous-champs doivent être initialisés avant la supreclasse! En attendant, l'exigence java nous "défend" de la spécialisation de la classe en spécialisant ce que l'argument du super constructeur
Dans les cas où une classe parente a un constructeur par défaut, l'appel à super est inséré automatiquement pour vous par le compilateur. Puisque chaque classe en Java hérite d'Object, le constructeur d'objets doit être appelé d'une manière ou d'une autre et il doit être exécuté en premier. L'insertion automatique de super () par le compilateur le permet. Faire en sorte que super apparaisse en premier, impose que les corps du constructeur soient exécutés dans le bon ordre qui serait: Object -> Parent -> Child -> ChildOfChild -> SoOnSoForth
(1) Vérifier que super est la première instruction n'est pas suffisant pour éviter ce problème. Par exemple, vous pouvez mettre "super (someMethodInSuper ());" dans votre constructeur. Cela tente d'accéder à une méthode dans la superclasse avant sa construction, même si super est la première instruction.
(2) Le compilateur semble implémenter une vérification différente qui est, à elle seule, suffisante pour éviter ce problème. Le message est "impossible de référencer xxx avant que le constructeur de supertype n'ait été appelé". Par conséquent, vérifier que super est la première déclaration n'est pas nécessaire
Veuillez parcourir ce http://valjok.blogspot.in/2012/09/super-constructor-must-be-first.html
la source
La chose la plus importante à garder à l'esprit est que cela
super.onPause()
appelle implicitementsetResult(Activity.RESULT_CANCELED)
. MaissetResult
ne peut être appelé qu'une seule fois et tous les appels suivants sont ignorés. Donc , si vous voulez pousser tout type de résultat à l'activité parent, vous devez appelersetResult
vous - même, avant de vous appelersuper.onPause()
. C'est le plus gros problème, pour autant que je sache.la source
super.onPause() implicitly calls setResult(Activity.RESULT_CANCELED)
. Pourriez-vous dire d'où vous avez obtenu ça?LES DEUX sont corrects IMO
Selon la documentation
Super
La méthode doit toujours être appelée lorsque la documentation le dit explicitement.Vous pouvez cependant choisir quand appeler la super méthode.
En regardant la source de
onPause
Par conséquent, peu importe avant ou après son appel. Tu devrais être bon.
Mais pour les meilleures pratiques, vous devriez l'appeler en premier.
Je le recommande surtout comme mécanisme de protection: s'il y a une exception, la
super
méthode d'instance aura déjà été appelée.Mettre également ces appels sur la première ligne vous aidera à éviter de commettre des erreurs à l'avenir telles que la suppression de code dans la méthode et la suppression accidentelle de l'appel à la super classe.
la source
Base Class
mais si vous remplacez, il est nécessaire que vous appeliez l'super
autre que vous aurezandroid.app.SuperNotCalledException
Vous dites que Google suggère la méthode 1, mais Dianne Hackborn, un ingénieur de framework Android bien connu suggère sinon voir le lien du forum Google .
Il est intuitif d'appeler la super classe en dernier lors de la destruction d' une instance dans les méthodes onPause, onStop et onDestroy et d' abord lors de la création d' une instance avec les méthodes onCreate, onResume et onStart .
la source
Le super des rappels est nécessaire pour mettre l'activité dans le bon état en interne pour le système.
Disons que vous démarrez votre activité et que onCreate est appelé par le système. Vous pouvez maintenant le remplacer et par exemple charger votre mise en page. Mais dans l'intérêt du flux du système, vous devez appeler super, pour que le système puisse continuer avec la procédure standard. C'est pourquoi une exception sera levée si vous ne l'appelez pas.
Cela se produit indépendamment de votre implémentation dans onCreate. C'est seulement important pour le système. S'il n'y avait pas d'ANR, vous pourriez avoir une boucle sans fin dans n'importe quel rappel et l'activité serait interceptée dans celui-là. Ainsi, le système sait quand le rappel est terminé et appelle le suivant.
Je ne connais qu'une seule situation, où le timing du super appel est nécessaire. Si vous souhaitez modifier le comportement standard du thème ou de l'affichage, etc. dans onCreate, vous devez le faire avant d'appeler super pour voir un effet. Sinon AFAIK il n'y a aucune différence à quel moment vous l'appelez.
Mais pour laisser le système faire ce qu'il peut le mieux, mettez le super dans la première ligne d'un rappel suivi de votre code, si vous n'avez pas de bonne raison de rompre avec lui.
la source