110 votes

Avertissement: Ne placez pas les classes de contexte Android dans des champs statiques. c'est une fuite de mémoire (et casse également Instant Run)

Android Studio:

Ne placez pas d'Android contexte classes de champs statiques; c'est un fuite de mémoire (et aussi des sauts Instantanés Exécuter)

Donc 2 questions:

#1 Comment appelez-vous un startService partir d'une méthode statique sans une variable statique pour le contexte?
#2 Comment faites-vous envoyer un localBroadcast partir d'une méthode statique (même)?

Exemples:

public static void log(int iLogLevel, String sRequest, String sData) {
    if(iLogLevel > 0) {

        Intent intent = new Intent(mContext, LogService.class);
        intent.putExtra("UPDATE_MAIN_ACTIVITY_VIEW", "UPDATE_MAIN_ACTIVITY_VIEW");
        mContext.startService(intent);
    }
}

ou

        Intent intent = new Intent(MAIN_ACTIVITY_RECEIVER_INTENT);
        intent.putExtra(MAIN_ACTIVITY_REQUEST_FOR_UPDATE, sRequest));
        intent.putExtra(MAIN_ACTIVITY_DATA_FOR_VIEW, sData);
        intent.putExtra(MAIN_ACTIVITY_LOG_LEVEL, iLogLevel);
        LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);

Quelle serait la bonne façon de le faire sans l'aide d' mContext?

REMARQUE: je pense que ma principale question pourrait être de savoir comment passer contexte d'une classe à partir de laquelle l'appel de la méthode des vies.

69voto

Marcus Points 434

Assurez-vous juste de passer contexte.getcontexteapplication() ou appelez getcontexteapplication() sur un contexte qui est transmis par l'intermédiaire des méthodes/constructeur de votre singleton si vous décidez de stocker dans n'importe quel champ de membre.

idiot proof exemple (même si quelqu'un devait passer dans une activité qu'elle va saisir le contexte de l'application et de l'utiliser pour instancier le singleton):

public static synchronized RestClient getInstance(Context context) {
    if (mInstance == null) {
        mInstance = new RestClient(context.getApplicationContext());
    }
    return mInstance;
}

getcontexteapplication() selon les docs: "Retourner le contexte de l'unique, de l'Application globale de l'objet de la procédure."

Cela signifie que le contexte retourné par "getcontexteapplication()" live à travers l'ensemble du processus et donc il n'a pas d'importance si vous stockez un point de référence fixe à n'importe où puisqu'il sera toujours là lors de l'exécution de votre application (et survivre à tous les objets/les singletons instancié par elle).

Comparer avec le contexte à l'intérieur des points de vue et les activités de l'organisation de grandes quantités de données, si vous avez une fuite d'un contexte tenue par une activité, le système ne sera pas en mesure de se libérer de cette ressource qui n'est évidemment pas bon.

Une référence à une activité de par son contexte doit vivre le même cycle de vie que l'activité elle-même, sinon il va tenir le contexte d'otages provoquant une fuite de mémoire (ce qui est la raison derrière la charpie avertissement).

EDIT: le gars bashing l'exemple de la doc ci-dessus, il y a même une section de commentaires dans le code sur ce que je viens d'écrire à propos de:

    // getApplicationContext() is key, it keeps you from leaking the
    // Activity or BroadcastReceiver if someone passes one in.

59voto

Viral Points 280

Il suffit de le transmettre en tant que paramètre à votre méthode. Il est inutile de créer une instance statique de Context uniquement dans le but de démarrer un Intent .

Voici à quoi devrait ressembler votre méthode:

 public static void log(int iLogLevel, String sRequest, String sData, Context ctx) {
    if(iLogLevel > 0) {

        Intent intent = new Intent(ctx, LogService.class);
        intent1.putExtra("UPDATE_MAIN_ACTIVITY_VIEW", "UPDATE_MAIN_ACTIVITY_VIEW");
        ctx.startService(intent);
    }
}
 

Mise à jour à partir des commentaires sur la question: Cascade le contexte de l'activité initiatrice (via les paramètres du constructeur ou les paramètres de la méthode) jusqu'au point où vous en avez besoin.

6voto

Licat Julius Points 343

C'est juste un avertissement. Ne t'inquiète pas. Si vous souhaitez utiliser un contexte d'application, vous pouvez l'enregistrer dans une classe "singleton", utilisée pour enregistrer toutes les classes singleton de votre projet.

3voto

Zoe Points 9634

En général, évitez d'avoir des champs contexte défini comme statique. L'avertissement lui-même s'en explique: C'est une fuite de mémoire. La rupture instantanée exécuter peut - être pas le plus gros problème sur la planète si.

Maintenant, il y a deux scénarios où vous obtenez ce message d'avertissement. Pour une instance (le plus évident):

public static Context ctx;

Et puis il y a le plus fastidieux, où le contexte est enveloppé dans une classe:

public class Example{
    public Context ctx;
    //Constructor omitted for brievety 
}

Et que la classe est définie comme statique quelque part:

public static Example example;

Et vous obtiendrez le message d'avertissement.

La solution elle-même est assez simple: Ne pas placer les champs contexte statique dans les instances, qu'il s'agisse d'un emballage de classe ou le déclarer statique directement.

Et la solution à l'avertissement est simple: ne pas placer le champ statique. Dans votre cas, passez le contexte comme un exemple de la méthode. Pour les classes où Contexte plusieurs appels sont effectués, appel à un constructeur pour passer le contexte (ou une Activité) à la classe.

Notez qu'il s'agit d'un avertissement, pas une erreur. Devez-vous pour quelque raison que ce soit besoin d' un contexte statique, vous pouvez le faire. Si vous créez une fuite de mémoire lorsque vous le faites.

2voto

Rene Dohan Points 766

Dans votre cas, il ne fait pas beaucoup de sens en tant que champ statique, mais je ne pense pas que c'est mauvais dans tous les cas. Si vous maintenant ce que vous faites, vous pouvez avoir un champ statique qui a le contexte et la valeur null, il plus tard. Je suis de la création d'instance statique pour mon modèle principal de la classe qui a le contexte à l'intérieur, son contexte d'application pas de contexte d'activité et aussi j'ai statique champ d'instance de la classe contenant de l'Activité que j'null sur les détruire. Je ne vois pas que j'ai de fuite de mémoire. Donc si certains gars intelligent que je me trompe n'hésitez pas à commenter...

Aussi Instantanée Exécuter fonctionne ici très bien...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X