Studio Android:
Ne placez pas de classes de contexte Android dans des champs statiques; il s'agit d'une fuite de mémoire (et interrompt également Instant Run)
Donc 2 questions:
# 1 Comment appeler a à startService
partir d'une méthode statique sans variable statique pour le contexte?
# 2 Comment envoyer un localBroadcast à partir d'une méthode statique (idem)?
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 faire cela sans utiliser mContext
?
REMARQUE: je pense que ma principale question pourrait être de savoir comment passer le contexte à une classe à partir de laquelle réside la méthode d'appel.
android
android-studio-2.2
John Smith
la source
la source
Réponses:
Passez-le simplement comme paramètre à votre méthode. Il n'y a aucun sens à créer une instance statique de
Context
uniquement dans le but de démarrer unIntent
.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: mettez en cascade le contexte de l'activité de lancement (via les paramètres du constructeur ou les paramètres de méthode) jusqu'au moment où vous en avez besoin.
la source
MyClass
ajoutez un constructeur public comme une méthodepublic MyClass(Context ctx) { // put this ctx somewhere to use later }
(Ceci est votre constructeur) Maintenant, créez une nouvelle instance d'MyClass
utilisation de ce constructeur, par exempleMyClass mc = new MyClass(ctx);
Assurez-vous simplement de passer context.getApplicationContext () ou d'appeler getApplicationContext () sur n'importe quel contexte qui est passé via des méthodes / constructeur à votre singleton si vous décidez de le stocker dans n'importe quel champ membre.
Exemple de preuve idiot (même si quelqu'un passait une activité, il récupérera le contexte de l'application et l'utilisera pour instancier le singleton):
public static synchronized RestClient getInstance(Context context) { if (mInstance == null) { mInstance = new RestClient(context.getApplicationContext()); } return mInstance; }
getApplicationContext () selon la documentation: "Renvoie le contexte de l'objet Application global unique du processus en cours."
Cela signifie que le contexte retourné par "getApplicationContext ()" vivra tout au long du processus et donc peu importe si vous y stockez une référence statique n'importe où, car il sera toujours là pendant l'exécution de votre application (et survivra à tous les objets / singletons instancié par lui).
Comparez cela au contexte à l'intérieur des vues / activités contenant de grandes quantités de données, si vous perdez un contexte détenu par une activité, le système ne pourra pas libérer cette ressource qui n'est évidemment pas bonne.
Une référence à une activité par son contexte doit vivre le même cycle de vie que l'activité elle-même, sinon elle tiendra le contexte en otage provoquant une fuite de mémoire (ce qui est la raison de l'avertissement de charpie).
EDIT: Pour le gars qui dénigre l'exemple de la documentation ci-dessus, il y a même une section de commentaires dans le code sur ce que je viens d'écrire:
// getApplicationContext() is key, it keeps you from leaking the // Activity or BroadcastReceiver if someone passes one in.
la source
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", qui est utilisée pour enregistrer toute la classe singleton de votre projet.
la source
Dans votre cas, cela n'a pas beaucoup de sens de l'avoir comme champ statique mais je ne pense pas que ce soit mauvais dans tous les cas. Si vous faites maintenant ce que vous faites, vous pouvez avoir un champ statique qui a un contexte et l'annuler plus tard. Je crée une instance statique pour ma classe de modèle principale qui a un contexte à l'intérieur, son contexte d'application et non un contexte d'activité et j'ai également un champ d'instance statique de classe contenant une activité que je vide lors de la destruction. Je ne vois pas que j'ai une fuite de mémoire. Donc, si un gars intelligent pense que je me trompe, n'hésitez pas à commenter ...
Instant Run fonctionne également très bien ici ...
la source
En général, évitez d'avoir des champs de contexte définis comme statiques. L'avertissement lui-même explique pourquoi: c'est une fuite de mémoire. La rupture de la course instantanée n'est peut-être pas le plus gros problème de la planète.
Maintenant, il y a deux scénarios où vous obtiendrez cet avertissement. Pour une instance (la plus évidente):
public static Context ctx;
Et puis il y a celui un peu plus délicat, où le contexte est enveloppé dans une classe:
public class Example{ public Context ctx; //Constructor omitted for brievety }
Et cette classe est définie comme statique quelque part:
public static Example example;
Et vous recevrez l'avertissement.
La solution elle-même est assez simple: ne placez pas de champs de contexte dans des instances statiques , qu'il s'agisse d'une classe d'encapsulation ou de la déclarer directement statique.
Et la solution à l'avertissement est simple: ne placez pas le champ de manière statique. Dans votre cas, transmettez le contexte en tant qu'instance à la méthode. Pour les classes où plusieurs appels de contexte sont effectués, utilisez un constructeur pour transmettre le contexte (ou une activité d'ailleurs) à la classe.
Notez que c'est un avertissement, pas une erreur. Si, pour une raison quelconque , vous avez besoin d' un contexte statique, vous pouvez le faire. Bien que vous créiez une fuite de mémoire lorsque vous le faites.
la source
Si vous vous assurez qu'il s'agit d'un contexte d'application. Cela compte. Ajoute ça
@SuppressLint("StaticFieldLeak")
la source
Utilisez
WeakReference
pour stocker le contexte dans les classes Singleton et l'avertissement sera partiprivate WeakReference<Context> context; //Private contructor private WidgetManager(Context context) { this.context = new WeakReference<>(context); } //Singleton public static WidgetManager getInstance(Context context) { if (null == widgetManager) { widgetManager = new WidgetManager(context); } return widgetManager; }
Vous pouvez maintenant accéder au contexte comme
if (context.get() instanceof MainActivity) { ((MainActivity) context.get()).startActivityForResult(pickIntent, CODE_REQUEST_PICK_APPWIDGET); }
la source