Google Analytics dans une application Android – traitant de multiples activités

J’étais très enthousiaste de voir à quel point il était facile de configurer Google Analytics avec mon application, mais le manque de documentation m’a amené à poser quelques questions. Les seules informations que je peux trouver proviennent directement de la documentation ici , qui ne traite que des rapports de pages et des événements d’une activité. Je souhaite signaler des vues de page et des événements sur plusieurs activités de mon application.

En ce moment dans le onCreate () de toutes mes activités, j’appelle:

tracker = GoogleAnalyticsTracker.getInstance(); tracker.start("UA-xxxxxxxxx", this); 

Et dans le onDestroy () de toutes mes activités:

  tracker.stop(); 

Je fais ensuite le suivi des vues et des événements de PageViews, au besoin, et les envoie avec une autre requête HTTP que je réalise. Mais je ne suis pas sûr que ce soit la meilleure façon. Dois-je appeler start () et stop () dans chaque activité, ou devrais-je seulement appeler start () et stop () dans mon activité principale de lanceur?

Le problème avec l’appel de start () / stop () dans chaque activité (comme suggéré par Christian) est qu’il en résulte une nouvelle “visite” pour chaque activité à laquelle l’utilisateur navigue. Si cela convient à votre utilisation, alors c’est bien, mais ce n’est pas comme cela que la plupart des gens s’attendent à ce que les visites se fassent. Par exemple, il serait très difficile de comparer des numéros Android à des numéros Web ou iPhone, car une “visite” sur le Web et sur l’iPhone correspond à une session et non à une page / activité.

Le problème avec l’appel de start () / stop () dans votre application est qu’il entraîne des visites longues et inattendues, car Android ne garantit pas la fin de l’application après la fermeture de votre dernière activité. De plus, si votre application effectue des opérations avec des notifications ou des services, ces tâches en arrière-plan peuvent démarrer votre application et entraîner des visites “fantômes”. UPDATE: stefano indique correctement que onTerminate () n’est jamais appelé sur un périphérique réel, il n’y a donc pas de place évidente pour mettre l’appel à l’arrêt ().

Le problème avec l’appel de start () / stop () dans une seule activité “principale” (comme suggéré par Aurora) est qu’il n’y a aucune garantie que l’activité restra pendant toute la durée d’utilisation de votre application par l’utilisateur. Si l’activité “principale” est détruite (par exemple pour libérer de la mémoire), vos tentatives ultérieures d’écriture d’événements dans GA dans d’autres activités échoueront car la session a été arrêtée.

En outre, il existe un bogue dans Google Analytics, au moins dans la version 1.2, qui lui permet de garder une référence forte au contexte que vous avez transmis au démarrage (), l’empêchant ainsi de récupérer des ordures après sa destruction. Selon la taille de votre contexte, cela peut être une fuite de mémoire importante.

La fuite de mémoire est assez facile à corriger, elle peut être résolue en appelant start () en utilisant l’application au lieu de l’instance d’activité elle-même. Les documents devraient probablement être mis à jour pour refléter cela.

par exemple. de l’intérieur de votre activité:

 // Start the tracker in manual dispatch mode... tracker.start("UA-YOUR-ACCOUNT-HERE", getApplication() ); 

au lieu de

 // Start the tracker in manual dispatch mode... tracker.start("UA-YOUR-ACCOUNT-HERE", this ); // BAD 

Concernant le moment d’appeler start () / stop (), vous pouvez implémenter une sorte de comptage manuel des références, en incrémentant un compte pour chaque appel à Activity.onCreate () et en décrémentant chaque onDestroy (), puis en appelant GoogleAnalyticsTracker.stop () le compte atteint zéro.

La nouvelle bibliothèque EasyTracker de Google s’en chargera pour vous.

Si vous ne pouvez pas sous-classer les activités EasyTracker, vous pouvez également l’implémenter manuellement dans votre propre classe de base d’activité:

 public abstract class GoogleAnalyticsActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Need to do this for every activity that uses google analytics GoogleAnalyticsSessionManager.getInstance(getApplication()).incrementActivityCount(); } @Override protected void onResume() { super.onResume(); // Example of how to track a pageview event GoogleAnalyticsTracker.getInstance().trackPageView(getClass().getSimpleName()); } @Override protected void onDestroy() { super.onDestroy(); // Purge analytics so they don't hold references to this activity GoogleAnalyticsTracker.getInstance().dispatch(); // Need to do this for every activity that uses google analytics GoogleAnalyticsSessionManager.getInstance().decrementActivityCount(); } } public class GoogleAnalyticsSessionManager { protected static GoogleAnalyticsSessionManager INSTANCE; protected int activityCount = 0; protected Integer dispatchIntervalSecs; protected Ssortingng apiKey; protected Context context; /** * NOTE: you should use your Application context, not your Activity context, in order to avoid memory leaks. */ protected GoogleAnalyticsSessionManager( Ssortingng apiKey, Application context ) { this.apiKey = apiKey; this.context = context; } /** * NOTE: you should use your Application context, not your Activity context, in order to avoid memory leaks. */ protected GoogleAnalyticsSessionManager( Ssortingng apiKey, int dispatchIntervalSecs, Application context ) { this.apiKey = apiKey; this.dispatchIntervalSecs = dispatchIntervalSecs; this.context = context; } /** * This should be called once in onCreate() for each of your activities that use GoogleAnalytics. * These methods are not synchronized and don't generally need to be, so if you want to do anything * unusual you should synchronize them yourself. */ public void incrementActivityCount() { if( activityCount==0 ) if( dispatchIntervalSecs==null ) GoogleAnalyticsTracker.getInstance().start(apiKey,context); else GoogleAnalyticsTracker.getInstance().start(apiKey,dispatchIntervalSecs,context); ++activityCount; } /** * This should be called once in onDestrkg() for each of your activities that use GoogleAnalytics. * These methods are not synchronized and don't generally need to be, so if you want to do anything * unusual you should synchronize them yourself. */ public void decrementActivityCount() { activityCount = Math.max(activityCount-1, 0); if( activityCount==0 ) GoogleAnalyticsTracker.getInstance().stop(); } /** * Get or create an instance of GoogleAnalyticsSessionManager */ public static GoogleAnalyticsSessionManager getInstance( Application application ) { if( INSTANCE == null ) INSTANCE = new GoogleAnalyticsSessionManager( ... ,application); return INSTANCE; } /** * Only call this if you're sure an instance has been previously created using #getInstance(Application) */ public static GoogleAnalyticsSessionManager getInstance() { return INSTANCE; } } 

Le SDK a maintenant une bibliothèque externe qui s’occupe de tout cela. Son appelé EasyTracker. Vous pouvez simplement l’importer et étendre l’activité ou ListActivity fournie, créer une ressource de chaîne avec votre code et vous avez terminé.

Le tracker suivra uniquement l’activité où il est exécuté. Alors, pourquoi ne pas sous- onCreate une activité qui démarre à chaque fois sur onCreate :

 public class GAnalyticsActivity extends Activity{ public void onCreate(Bundle icicle){ super.onCreate(icile); tracker = GoogleAnalyticsTracker.getInstance(); tracker.start("UA-xxxxxxxxx", this); } // same for on destroy } 

Ensuite, vous prolongez cette classe pour chaque activité que vous utilisez:

 public class YourActivity extends GAnalyticsActivity{ public void onCreate(Bundle icicle){ super.onCreate(icile); // whatever you do here you can be sure // that the tracker has already been started } } 

L’approche que j’utilise consiste à utiliser un service de liaison (j’en utilise déjà un, ce qui évite la création de code de plaque de chaudière supplémentaire).

Un service lié ne durera que tant qu’il y aura des activités liées à celui-ci. Toutes les activités de mon application sont liées à ce service et ne durent que tant que l’utilisateur utilise activement mon application, ce qui en fait une véritable «session».

Je démarre le tracker avec une instance singleton d’Application que j’ai étendue et a ajouté une méthode getInstance () statique pour récupérer l’instance:

 // Non-relevant code removed public IBinder onBind(Intent intent) { tracker = GoogleAnalyticsTracker.getInstance(); tracker.startNewSession(PROPERTY_ID, MyApp.getInstance()); } public boolean onUnbind(Intent intent) { tracker.stopSession(); } 

Voir: http://developer.android.com/guide/topics/fundamentals/bound-services.html

J’ai fait une répartition temporelle entre les visites dans mon application, fonctionnant comme ceci:

J’ai créé un object wrapper singleton Tracker pour GoogleAnalyticsTracker où je garde la dernière fois que quelque chose a été suivi. Si ce temps est plus que x secondes, je le traite comme une nouvelle visite.

Bien sûr, cela n’est utile que si vous suivez tout ce qui se trouve dans votre application, et que cela peut ne pas être la meilleure solution dans toutes les situations, mais cela fonctionne bien pour mon application.

Il ne prend en charge que trackPageView, mais setCustomVar et trackEvent doivent être facilement implémentés.

N’importe où vous devez suivre quelque chose, ajoutez simplement la ligne:

  Tracker.getInstance(getApplicationContext()).trackPageView("/HelloPage"); 

Je le fais habituellement dans le onResume d’une activité

Suivi de l’essentiel

Vous aurez besoin de quelque chose comme ceci: http://mufumbo.wordpress.com/2011/06/13/google-analytics-lags-on-android-how-to-make-it-responsive/

C’est sur la version précédente et fonctionnait très bien. Maintenant, je suis dans la même lutte que vous, car V2 ne semble pas être très cohérent.

Je me demande si cela pourrait être fait en utilisant AOP.

Android ne peut utiliser que des méthodes AOP à la compilation, donc peut-être quelque chose comme AspectJ?

Il y a un peu plus d’informations sur l’utilisation d’AspectJ dans Android dans ce fil de discussion . Le principal problème est que vous devez toujours déclarer les classes que vous possédez.