Android: erreur OutOfMemory et le backstack

La feuille suivante représente le flux de travail dans l'application sur laquelle se pose cette question.

Flux de travail

  • Verrouiller le téléphone Android après l'utilisateur composer un numéro de téléphone
  • Comment créer une conception de matériau comme une barre de défilement personnalisée avec des chiffres et des bulles d'alphabets en vue récente
  • La meilleure façon de gérer les événements dans Android
  • L'erreur "Essayer d'utiliser un bitmap recyclé"?
  • @ Font-face ne fonctionne pas dans Webkit mobile
  • Les fragments sont remplacés tandis que AsyncTask est exécuté - NullPointerException sur getActivity ()
  • J'ai rencontré des problèmes avec OutOfMemory Errors, principalement parce que les utilisateurs pouvaient passer de l'activité B à l'activité D à plusieurs reprises (ils montrent un contenu différent pour chaque tentative), sans que l'activité précédente soit détruite. Cela a conduit à un très grand backstack résultant en une erreur OutOfMemory.

    Pour éviter cela, j'ai suivi la recommandation d'ajouter des activités parent au manifeste et de créer de nouveaux backstacks avec la classe TaskStackBuilder:

    void openDFromB() { Intent i = new Intent(this, ActivityD.class); TaskStackBuilder.create(this) .addParentStack(ActivityD.class) .addNextIntent(i) .startActivities(); } 

    Si un utilisateur passe maintenant de l'activité B à D, MainMenu, A et B sont détruites et un nouveau Backstack (MainMenu, C, D) est créé. Cela résout mes problèmes de mémoire pour le niveau api supérieur 10, mais malheureusement, TaskStackBuilder ne crée pas de backstacks pour les périphériques pré-11.

    Une idée de ce qu'il faut faire pour éviter que les utilisateurs empilent des quantités infinies d'activités avant l'api 11? Est-ce que cela est possible ou dois-je essayer de libérer autant de ressources que possible sur onPause pour gagner une quantité maximale d'activités empilées avant OoM?

    Merci d'avance!

  • Android: clickable = "true" signifie qu'il n'est pas cliquable?
  • Comment mettre des tailles d'icônes d'application correctes dans Android, y compris pour Amazon Kindle Fire?
  • Calling finish () sur une activité Android ne termine pas réellement
  • Rappel dans Android?
  • Android: java.lang.IllegalAccessException lors de la tentative d'utilisation d'une classe "Application" personnalisée
  • Android: java.lang.OutOfMemoryError: Impossible d'attribuer une allocation d'octets 23970828 avec 2097152 octets gratuits et 2 Mo jusqu'à OOM
  • 5 Solutions collect form web for “Android: erreur OutOfMemory et le backstack”

    La réponse de Zabri est bonne, mais je proposerais une autre est probablement meilleure: vous ne fermez pas toutes les activités, mais lorsque vous ouvrez une nouvelle activité qui a été ouverte, vous dites au système qu'elle peut effacer le chemin du retour et rouvrir celle-ci, Bien sûr, avec une nouvelle intention et toutes les nouvelles données dont vous avez besoin.

    Donc, si vous faites A – B – D – B – D – B, au lieu d 'avoir cette grande pile, vous aurez

    1. UN B
    2. A – B – D
    3. UN B
    4. A – B – D
    5. UN B

    Donc, si vous faites C – D – B – D – B – D, votre pile sera

    1. C – D
    2. C – D – B
    3. C – D
    4. C – D – B
    5. C – D

    etc. De cette façon, je pense que la pile reflète réellement ce que l'utilisateur peut avoir à l'esprit, et aussi la navigation est très logique, vous n'avez même pas besoin de captre bouton arrière pour que la navigation soit logique (bien sûr, vous pouvez le faire si Vous voulez une expérience utilisateur plus spécifique)

    Le code pour y parvenir est: créer une fonction qui reçoit une classe (quelque chose comme ActivityD.class), vous créez une intention, avec les indicateurs Intent.FLAG_ACTIVITY_CLEAR_TOP et Intent.FLAG_ACTIVITY_NEW_TASK et ensuite lorsque vous devez ouvrir une activité, juste Appelez cette fonction. Vous ne vous souciez pas si l'activité se trouve dans la pile ou non. Si ce n'est pas le cas, il est créé normalement.

      protected void startActivity(Class<?> clase) { final Intent i = new Intent(this, clase); int flags = Intent.FLAG_ACTIVITY_CLEAR_TOP; flags |= Intent.FLAG_ACTIVITY_NEW_TASK; i.setFlags(flags); startActivity(i); } startActivity(ActivityD.class); 

    Essaye ça-

     Intent intent = new Intent(getApplicationContext(),yourActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); 

    Une autre solution est:

    Définir android:noHistory="true" sur l'activité dans votre fichier manifeste supprime une activité de la pile chaque fois qu'elle est déplacée.

    Mais la façon la plus appropriée est d'appeler la méthode finish() chaque fois que vous démarrez une nouvelle activité comme dans l'exemple de code suivant:

     Intent intent = new Intent(this, yourActivity.class); startActivity(intent); finish(); 

    Vous pouvez également créer un récepteur de diffusion personnalisé et l'enregistrer dans toutes les activités qui peuvent être déclenchées lors de l'événement de votre choix. Pour plus d'aide, vous pouvez vérifier ce lien .

    Peut-être que votre application ait des fuites de mémoire et que les activités plus anciennes ne soient pas récupérées par le GC et que, éventuellement, la taille du tas augmentera, tout changement d'activité se produira.

    Comment trouver des fuites?
    Regardez: http://www.youtube.com/watch?v=_CruQY55HOk

    Les références:

    1. http://android-developers.blogspot.in/2011/03/memory-analysis-for-android.html .
    2. http://kohlerm.blogspot.in/2009/07/eclipse-memory-analyzer-10-useful.html

    Je ne sais pas comment cela fonctionne avec le tiroir de navigation, mais je créais une application Android il y a quelque temps, qui a commencé avec un écran de chargement, puis déplacé vers l'activité principale de l'application. Comme je n'avais pas besoin de vouloir retourner à l'écran de chargement, je viens d'appeler finish() avant de passer à l'activité principale. Comme ça:

     Intent intent = new Intent(this, MainActivity.class); startActivity(intent); finish(); 

    Et puis, lorsque l'utilisateur a appuyé sur le bouton arrière de l'activité principale, ils n'ont pas eu accès à l'activité de chargement, mais là où ils étaient avant même.

    Donc, vous pouvez également essayer de faire ceci:

     void openDFromB() { Intent i = new Intent(this, ActivityD.class); startActivity(i); finish(); } 

    Comme je l'ai dit, je n'ai jamais mis en place un tiroir de navigation, mais quelque chose me dit que cela pourrait rompre tout son comportement. En outre, appeler finish() dans une activité est un concept de base que je serais surpris si vous ne l'aviez déjà essayé. 🙂 Mais encore, je le publie comme un coup dans le noir, au cas où cela vous aiderait. Bonne chance. 🙂

    Bonjour, vous pouvez essayer d'ajouter la déclaration suivante dans votre fichier manifeste sous la balise de l'application:

     android:largeHeap="true" 

    Assurez-vous également que votre android:targetSdkVersion soit 14.

    coAndroid est un fan Android de Google, tout sur les téléphones Android, Android Wear, Android Dev et Android Games Apps.