J'exécute mon application avec StrictMode activé en développement comme indiqué ici StrictMode pour les versions de plate-forme inférieures et j'ai remarqué un message d'erreur indiquant que je ne sais pas quoi penser et que je ne peux trouver aucune référence.
J'ai un Android.os.StrictMode$InstanceCountViolation
avec des valeurs pour instances
et limit
par exemple.
instances = 3; limite = 2
Maintenant je me demande:
Des idées?
La clé est StrictMode.sExpectedActivityInstanceCount
et incrementExpectedActivityCount
et decrementExpectedActivityCount
:
ActivityThread.performLaunchActivity
Activity
.ActivityThread.performDestroyActivity
Ainsi, le limit
est moindre à chaque fois qu'une activité est détruite, mais si une instance est divulguée, le nombre d'instances réel sera supérieur à la limite, pour détecter si elle est divulguée, ils font de la magie GC (dans decrementExpectedActivityCount
):
System.gc();
System.runFinalization(); // added in https://github.com/Android/platform_frameworks_base/commit/6f3a38f3afd79ed6dddcef5c83cb442d6749e2ff
System.gc();
si après cela, le GC n'a pas supprimé l'activité de la mémoire de l'application, cela est considéré comme une fuite.
Sur la base de ce qui précède, le seul moyen d'empêcher est de s'assurer qu'il n'y a aucune référence à l'activité incriminée après onDestroy
. Le problème est que certains peuvent être des WeakReference
s qui sont toujours accessibles via certains objets natifs, qui semblent avoir un cycle de vie différent. Voici comment je suis arrivé à cette conclusion:
MyActivity
et avoir vu le message du journalselect * from instanceof full.package.name.of.MyActivity
Si nous augmentons le nombre initialement nous aurons plus d'espace pour les jambes avant de signaler la fuite pour des classes spécifiques:
// Application.onCreate or nearby where you set up StrictMode detectActivityLeaks
Method incrementExpectedActivityCount = StrictMode.class.getMethod("incrementExpectedActivityCount", Class.class)
incrementExpectedActivityCount.invoke(null, MyActivity.class);
incrementExpectedActivityCount.invoke(null, MyActivity2.class);
Il semble qu'il puisse y avoir un bogue dans la vérification de StrictMode sur certains appareils.
Si une activité est démarrée, puis fermée et redémarrée très rapidement, vous pouvez obtenir un StrictMode.InstanceCountViolation.
Cependant, c'est simplement parce que le garbage collector n'a pas encore finalisé la première instance de l'activité, ce qui signifie qu'il y a temporairement 2 (ou plus) instances en mémoire.
L'appel de System.gc () avant startActivity () ou startActivityForResult () arrêtera StrictMode.InstanceCountViolation.
Cela semble indiquer un bogue (ou peut-être une fonctionnalité?) Dans la vérification StrictMode.
Voici une discussion sur les groupes Google sur la gestion de StrictMode InstanceCountViolation . Il semble que chaque version différente de Android ait une politique différente, ils semblent donc la désactiver. Les documents Android parlent également de Mode strict
Mais ne vous sentez pas obligé de réparer tout ce que StrictMode trouve. En particulier, de nombreux cas d'accès au disque sont souvent nécessaires pendant le cycle de vie normal des activités. Utilisez StrictMode pour trouver des choses que vous avez faites par accident. Cependant, les requêtes réseau sur le thread d'interface utilisateur sont presque toujours un problème.
Je pense que c'est ce que @sri essaie de montrer avec son code.
public class MyApplication extends Application {
@Override
public void onCreate (){
super.onCreate();
// when you create a new application you can set the Thread and VM Policy
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectCustomSlowCalls() // API level 11, to use with StrictMode.noteSlowCode
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.penaltyFlashScreen() // API level 11
.build());
//If you use StrictMode you might as well define a VM policy too
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects() // API level 11
.setClassInstanceLimit(Class.forName(“com.apress.proandroid.SomeClass”), 100)
.penaltyLog()
.build());
}
}
Ma compréhension est que cette violation est utilisée pour détecter les fuites de mémoire. Donc, à ce stade, vous ne devriez avoir que 2 instances de la classe chargées, mais le VM en a trouvé 3.
J'ai également vu cette violation dans mon code, mais mes instances supplémentaires ont toutes été référencées par des pointeurs faibles. J'ai donc choisi de désactiver cette règle.