Alternative à l’appel direct onResume ()

Je suis en onResume() réécrire mon application Android pour éliminer les appels directs à onResume() .

Mon application effectue actuellement la majeure partie de son travail dans onResume() , puis affiche l’affichage et c’est la fin de onResume() .

 @Override public void onResume() { super.onResume(); // get current date and time, // and determine if daylight savings time is in effect. //...600 lines of code // output both the chart and report // image.setImageBitmap(heightChart); report.setImageBitmap(reportBitmap); } 

L’étape suivante consiste à collecter les entrées de l’utilisateur, qui m’indiquent les modifications apscopes au rapport souhaité par l’utilisateur. (Il peut s’agir d’un nouvel emplacement, d’une nouvelle date ou d’un nouveau style d’affichage, etc.). Cela se fait comme suit:

 @Override public boolean onOptionsItemSelected(MenuItem item) { final int STATION_REQUEST = 1; int test = 1; switch (item.getItemId()) { case R.id.refresh: { userDateSet = false; onResume(); return true; } // come to the present. //...200 lines of code default: return super.onOptionsItemSelected(item); } } 

Comme le montre l’exemple, la sortie est régénérée en appelant onResume() après la détermination de la nouvelle commande utilisateur. C’EST MAUVAIS PRATIQUE, JE LE SAIS DÉJÀ !! Pourtant, cela fonctionne bien, dans la mesure où je l’ai déterminé, honnêtement, je ne comprends pas le problème.

Ma solution en tête est de rassembler les 600 lignes de code dans une routine distincte et de l’appeler à la place, à la fois depuis onResume() et de nombreux points dans onOptionsItemSelected()

 @Override public void onResume() { super.onResume(); myOnResumeCode(); } 

Et à l’intérieur onOptionsItemSelected() faire ceci

 @Override public boolean onOptionsItemSelected(MenuItem item) { final int STATION_REQUEST = 1; int test = 1; switch (item.getItemId()) { case R.id.refresh: { userDateSet = false; myOnResumeCode(); return true; } // come to the present. ... // Other statements } 

Cette méthode est-elle acceptable? Dans le cas contraire, toute suggestion ne permettant pas de “réécrire le tout” me sera très utile. J’ai longuement cherché une solution propre, mais je n’ai pas trouvé de solution que je puisse comprendre. Je vous remercie.

Honnêtement, je ne comprends pas le problème avec cela.

L’ onResume() votre méthode onResume() est inoffensive en soi. Mais l’appel à sa super méthode super.onResume(); laissera le système penser qu’il s’agit d’une autre occurrence de l’événement de reprise. Cela entraînera une utilisation inutile des ressources pour actualiser les vues et les travaux internes similaires. Vous devez donc éviter les appels explicites aux méthodes de rappel du cycle de vie, quelles que soient les circonstances.

Cette méthode est-elle acceptable?

Le nombre de lignes de code ne le rend pas acceptable ou non. C’est une question que vous devez vous poser . Si vous pensez que tout le code doit être exécuté lors de cet événement, vous devriez le faire. Sinon, vous pourriez économiser des ressources.

Si vous faites quelque chose comme ça

 public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.mnuEnableSomething: { refreshTheWholeUi(); return true; } case R.id.mnuClearList: { refreshTheWholeUi(); return true; } } } public void onResume() { super.onResume(); refreshTheWholeUi(); } 

Le changer ensuite en vaudra la peine.

 public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.mnuEnableSomething: { enableIt(); return true; } case R.id.mnuClearList: { justClearTheList(); return true; } } } public void onResume() { super.onResume(); refreshTheWholeUi(); } 

Maintenant, au coeur du sujet

Après votre réponse, j’ai examiné de plus près votre question et cela m’a frappé.

Mon plan est de déplacer ces 600 lignes dans un fichier de classe séparé. Cela les protégera des dommages pendant que je travaille sur le décodeur de commande dans le fichier source d’activité

Pas maintenant. Mais tu es vraiment proche. Oubliez toutes les complexités telles que le cycle de vie d’une activité, les méthodes, les classes etc. et concentrez-vous simplement sur le niveau d’exécution de base d’un programme informatique.

Un programme est toujours exécuté ligne par ligne. Comment avez-vous arrangé le code? Une bonne structuration du programme en méthodes, classes, etc. est pour le confort du programmeur. Pour le système, c’est toujours une série de lignes. Par conséquent, lorsqu’il s’acquitte de lourdes tâches, l’interface utilisateur risque de ne plus réagir car elle doit attendre son tour.

Alors comment est-il possible de travailler en parallèle?

Multi-Threading …!

Ce n’est pas si compliqué que ça en a l’air.

Vous devez localiser la partie la plus cruciale de votre code qui utilise davantage les ressources et le déplacer vers un autre thread.

J’ai illustré comment faire du multi-threading ici.

 public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.mnuProceessImageAction: { //Let user know that a background operation is running //with a progressbar or something processImage(mImage); return true; } } } private void processImage(Object image) { new Thread(new Runnable(){ public void run() { //Doing all the heavy duty here. //............................. //Now you have the result. Use it to update the UI. //(UI can be updated only from the UI thread) runOnUiThread(new Runnable(){ public void run() { updateTheUiWithTheImage(proccessedImage); } }); } }).start(); } private void updateTheUiWithTheImage(Object image) { try { //Hide progressbar if you have one //Now it wont make the UI to struggle to use it. } catch(NullPointerException e) { e.printStackTrace; } } 

C’est la forme la plus basique. Bien sûr, il existe des alternatives (comme AsyncTask ). Vous pouvez trouver plus d’informations à ce sujet facilement en ligne (essayez de rechercher “multi threading dans Android”). N’hésitez pas à demander plus.

Pourtant, cela fonctionne bien, dans la mesure où je l’ai déterminé, honnêtement, je ne comprends pas le problème.

Vous supposez que l’appel de super.onResume() est approprié dans les cas où vous appelez manuellement onResume() . Ce n’est pas une hypothèse sûre.

Cette méthode est-elle acceptable?

C’est certainement une amélioration et qui en vaut la peine.

600 lignes de code est une méthode très longue. Vous échoueriez à de nombreuses révisions de code, les réviseurs vous demandant de refactoriser ce code pour qu’il soit plus facile à gérer. En outre, selon ce que vous faites dans ces 600 lignes, il peut être préférable de déplacer cette logique vers un fil d’arrière-plan.

Considérons le code source onResume() qui est exécuté à chaque super.onResume() :

 protected void onResume() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this); getApplication().dispatchActivityResumed(this); mActivityTransitionState.onResume(); mCalled = true; } 

mActivityTransitionState.onResume() appelle resetViews() avec d’autres actions sur les vues de la fenêtre. Ainsi, bien que vous ayez constaté que cela fonctionne, toutes les invocations de méthodes font perdre du temps processeur et sont en fait redondantes, ce qui permet de conclure que la première approche est inefficace.

D’autre part, l’intention d’utiliser myOnResumeCode() sans appeler super.onResume() évite les appels de méthode inutiles et constitue une solution plus optimisée.

De plus, 600 lignes de code représentent une sum considérable. Si ces lignes sont exécutées sur le thread principal, l’interface utilisateur se bloque, ce qui rend l’application moins réactive. Il est préférable de faire les calculs sur un fil d’arrière-plan et de publier les modifications de vue sur le fil principal.

Je n’entends pas craindre de NE PAS appeler super dans mon code.

Cela semble être une incompréhension de ce à quoi servent les méthodes du cycle de vie d’ Activity . Ces méthodes sont des rappels que le système utilise pour informer les écouteurs des événements qui s’y produisent. Et vous avez reçu une telle notification une fois que onResume() été appelé par le système. Si vous supprimez super.onResume() vous obtiendrez une exception. Elle est clairement indiquée dans le code source lié et constitue la seule requête que le système “souhaite” que Ativity exécute lors de l’appel de son onResume() . Cela s’applique à toutes les autres méthodes du cycle de vie – pour être informé par le système d’exploitation. Le système ne se soucie pas de savoir si Activity appelle à nouveau, “manuellement”. onResume() l’ Activity est au premier plan, vous pouvez appeler onResume() autant que vous le souhaitez, afin de perdre du temps processeur et de rendre votre application moins réactive pour les utilisateurs.

Encore une fois, onResume() est un callback (“écouteur”) et ne peut pas affecter le comportement du système contrairement à, par exemple, la méthode finish() qui affecte le comportement du système en disant: “Hé, système, je suis tout fait et je veux être tué par vous “. Ce type de méthodes peut être traité comme une requête adressée au système.

Mettre à jour

Est-ce qu’ils vous disent même où mettre votre code d’application?

Vous êtes libre de mettre votre code où vous voulez. Le système vous informe simplement via les appels de méthode de cycle de vie lorsque, par exemple, votre contenu est visible pour l’utilisateur ou caché. Il s’agit donc de placer votre code dans un “endroit” raisonnable, en fonction des événements du cycle de vie.

Est-ce que cet état permet d’appeler directement onResume ()? Il existe de telles interdictions fermement énoncées.

C’est inutile, mais fonctionne comme vous l’avez vu. “Tu ne mangeras pas de viande le vendredi” , mais qui a dit que tu ne pouvais pas? 🙂

Pourtant, cela fonctionne bien, dans la mesure où je l’ai déterminé, honnêtement, je ne comprends pas le problème.

Je pense que @CommonsWare et d’autres ont déjà signalé le problème que vous rencontrez en cas d’appel de la fonction onResume lors de la mise à jour de vos éléments d’UI sur la base de l’interaction de l’utilisateur.

Cette méthode est-elle acceptable? Dans le cas contraire, toute suggestion ne permettant pas de “réécrire le tout” me sera très utile.

600 lignes de code ne sont pas toujours maintenables. Vous pourriez envisager de les diviser en plusieurs fonctions. Cependant, de mon sharepoint vue, il est toujours difficile de tout rassembler à partir d’un seul endroit.

Je vous recommande fortement d’utiliser ViewModel dans votre cas. La mise en œuvre et la gestion deviendront beaucoup plus simples. Je joins l’exemple d’implémentation à partir de la documentation du développeur .

 public class UserActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.user_activity_layout); final UserModel viewModel = ViewModelProviders.of(this).get(UserModel.class); viewModel.userLiveData.observer(this, new Observer() { @Override public void onChanged(@Nullable User data) { // update ui. } }); findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { viewModel.doAction(); } }); } } 

ViewModel serait comme ça.

  public class UserModel extends ViewModel { public final LiveData userLiveData = new LiveData<>(); public UserModel() { // trigger user load. } void doAction() { // depending on the action, do necessary business logic calls and update the // userLiveData. } } 

Lors de votre action sur certaines données résidant dans votre ViewModel , l’interface utilisateur sera mise à jour car nous avons implémenté la fonction de rappel qui est onChange .

L’idée d’implémenter des fonctions de rappel peut être réalisée de plusieurs manières (par exemple, en définissant une interface et en remplaçant la fonction). Un code est beaucoup plus propre s’il peut être appliqué correctement.

Et à partir de la documentation de ViewModel

ViewModel peut également être utilisé comme couche de communication entre différents Fragments d’une Activity . Chaque Fragment peut acquérir le ViewModel utilisant la même clé via son Activity . Cela permet la communication entre les fragments de manière découplée, de sorte qu’ils n’ont jamais besoin de parler directement à l’autre Fragment .

 public class MyFragment extends Fragment { public void onStart() { UserModel userModel = ViewModelProviders.of(getActivity()).get(UserModel.class); } } 

Maintenant, je pense que votre problème devient beaucoup plus simple. Vous pouvez également envisager de diviser vos éléments d’interface utilisateur en plusieurs Fragment et de gérer les mises à jour avec différents éléments de cycle de vie.

J’espère que cela pourra aider!

void protégé onResume ()

Appelé après onRestoreInstanceState (Bundle), onRestart () ou onPause () pour que votre activité commence à interagir avec l’utilisateur.

Gardez à l’esprit onResume n’est pas le meilleur indicateur du fait que votre activité est visible pour l’utilisateur. une fenêtre système telle que le protège-clavier peut être à l’avant. Utilisez onWindowFocusChanged(boolean) pour savoir avec certitude que votre activité est visible pour l’utilisateur (par exemple, pour reprendre un jeu).

Cela fournit des informations sur l’état du focus global, géré indépendamment des cycles de vie des activités. En tant que tel, bien que les changements de focus aient généralement une relation avec les changements de cycle de vie (une activité arrêtée ne sera généralement pas centrée sur la fenêtre), vous ne devez pas vous fier à un ordre particulier entre les rappels ici et ceux des autres méthodes de cycle de vie, comme onResume()

Void protégé onSaveInstanceState (Bundle outState)

Appelé pour récupérer un état par instance d’une activité avant d’être tué, afin qu’il puisse être restauré dans onCreate (Bundle) ou onRestoreInstanceState (Bundle) (le Bundle rempli par cette méthode sera transmis aux deux).

Voici mon codage final, merci à Ahamad pour ses excellents conseils. Je n’appelle jamais onResume () maintenant. Dans divers endroits, j’appelle myOnResume (). Le code part1 () correspond à tous les calculs étendus. Le code part2 () représente toutes les opérations de sortie.

 @Override public void onResume() { super.onResume();// myOnResume(); }// end: onResume. void myOnResume() { new Thread(new Runnable() { public void run() //run #1 { part1(); // do all the calculations in background. runOnUiThread(new Runnable() { public void run() //run #2 { part2(); // do the display in the UI thread. } //end of run#2 }); //end of runOnUiThread } //end of run#1 }).start(); } //end: myOnResume() 

C’est une habitude très courante chez les développeurs d’appeler les méthodes du cycle de vie pour effectuer certaines tâches, car cela s’avère pratique .

Mais le code actuel doit être correctement modularisé.

Puisque vous réécrivez le code, je vous recommanderais de migrer vers une architecture MVVM ou MVP car la gestion des cas que vous avez mentionnés est meilleure avec ces architectures.

Que vous utilisiez l’architecture ou non, il est bon de scinder le code en fonction de vos objectives.

Par exemple, onResume() signifie ce que vous faites lorsque l’ Activity/Fragment reprend. Et même chose pour onCreate() , onDestroy() etc.

De façon générale,
1. Nous initialisons les variables non changeantes dans onCreate et les onDestroy dans onDestroy .
2. Nous récupérons les données depuis le backend ou actualisons l’interface utilisateur dans onResume()
3. Nous mettons en pause tout processus en cours tel que la lecture multimédia dans onPause()
etc

Selon votre exemple de code, vous avez mentionné environ 600 lignes, ce qui, je suppose, n’effectue pas la même tâche.

Donc, vous devez diviser le code en fonction de la tâche

 private void refreshDayLightTime(){ //refresh your time } private void performRefreshTasks(){ //series of codes that are to be executed one after the other //ideally this method should call methods which perform specific tasks. } private void updateLaunchViews(Bitmap heightChart, Bitmap reportBitmap){ image.setImageBitmap(heightChart); report.setImageBitmap(reportBitmap); } 

L’utilisation de cette approche garde votre code propre. Et surtout, vous ne finissez pas par casser les cycles de vie de l’application. Et vous pouvez contrôler quelle action appeler à partir de quelle partie de l’application.

Il est toujours conseillé d’utiliser n’importe quel code accessible / maintenable.

Je suggérerais plutôt non seulement de déplacer votre code vers un élément maintenable , mais également de refactoriser l’implémentation en suivant l’une quelconque des méthodes qui séparent la couche de présentation de la logique.

Par exemple, Android Model View Presenter / MVP avec exemple de travail

Maintenant, si vous pouviez passer par une explication plus simple (explication plus simple pour MVP ), la possibilité d’ un débogage plus facile , d’un test unitaire et d’un code maintenable est évidente.

En venant à vos points (ce que @CommonsWare a déjà expliqué), déplacer l’ensemble des 600 lignes de code en tâche de fond ou en tâche asynchrone améliorera les performances de votre application. Maintenant, vous ne verrez plus le message comme ci-dessous.

entrez la description de l'image ici

Honnêtement, je ne comprends pas le problème


Déclaration de référence sur ce qui pourrait être inclus dans onResume() de developer.android

Par conséquent, toute méthode qui s’exécute dans le thread d’interface utilisateur doit faire le moins de travail possible sur ce thread. En particulier, les activités doivent mettre en place le moins possible les méthodes de cycle de vie clés telles que onCreate () et onResume (). Des opérations potentiellement longues, telles que des opérations réseau ou de firebase database, ou des calculs coûteux, tels que le redimensionnement de bitmaps, doivent être effectués dans un thread de travail (ou, dans le cas d’opérations de bases de données, via une requête asynchrone).


Les méthodes de vie Android sont supposées être invoquées par le système, en appelant le super onResume / super onPause . onPause permet au système d’allouer / de désallouer des ressources. Bien sûr, nous pouvons étendre la convivialité en appelant des méthodes enfant à l’intérieur de onResume() , onPause() etc. Cependant, il n’est pas conseillé de garder une logique métier dans ces méthodes et de les appeler.

Dans le cas de MVP , vous trouverez ci-dessous les lignes de guilde pouvant être suivies. Pour l’instant, il n’y a pas de définition standard / solide, comment atteindre la même chose. Néanmoins, l’échantillon que j’ai fourni est un bon sharepoint départ.

  1. Code séparé pour la vue. Garder les vues aussi bêtes que possible
  2. Conserver toute la logique métier dans les classes de présentateur
  3. Les modèles sont des interfaces responsables de la gestion des données