Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Analytics in Android app - dealing with multiple activities

I was pretty excited to see how easy it is to set up Google Analytics with my app, but the lack of documentation has me sitting with a few questions. The only information that I can find is right from the documentation here, which only looks at reporting PageViews and Events from one Activity. I want to report PageViews and Events across multiple Activities in my app.

Right now in the onCreate() of all of my activities, I am calling:

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

And in the onDestroy() of all of my activities:

    tracker.stop(); 

I then track PageViews and Events as needed, and Dispatch them along with another HTTP request I am performing. But I'm not so sure this is the best way. Should I be calling start() and stop() in each activity, or should I only call start() and stop() in my main launcher activity?

like image 681
Aurora Avatar asked Jul 09 '10 21:07

Aurora


People also ask

Can Google Analytics track app installs?

Install tracking is automatically enabled in Analytics for Android apps. You don't have to do anything!

Can Google Analytics be used for Mobile Apps?

Use Tag Manager with Google Analytics and Firebase. To get the latest mobile app report features in Google Analytics, use Firebase in your Android and iOS apps. Once enabled in your app, Google Analytics will automatically collect and report on built-in events and user properties.

How many activities should an app have?

Typically, one activity in an app is specified as the main activity, which is the first screen to appear when the user launches the app. Each activity can then start another activity in order to perform different actions.

How do I integrate Google Analytics into an Android app?

Go to Analytics and select the Analytics account you registered the app with. If you're unsure, look for the Analytics tracking ID in the google-services. json file you added to your project earlier. Copy that ID to the Analytics account search in the report drop-down.


2 Answers

The problem with calling start()/stop() in every activity (as suggested by Christian) is that it results in a new "visit" for every activity your user navigates to. If this is okay for your usage, then that's fine, however, it's not the way most people expect visits to work. For example, this would make comparing android numbers to web or iphone numbers very difficult, since a "visit" on the web and iphone maps to a session, not a page/activity.

The problem with calling start()/stop() in your Application is that it results in unexpectedly long visits, since Android makes no guarantees to terminate the application after your last activity closes. In addition, if your app does anything with notifications or services, these background tasks can start up your app and result in "phantom" visits. UPDATE: stefano properly points out that onTerminate() is never called on a real device, so there's no obvious place to put the call to stop().

The problem with calling start()/stop() in a single "main" activity (as suggested by Aurora) is that there's no guarantee that the activity will stick around for the duration that your user is using your app. If the "main" activity is destroyed (say to free up memory), your subsequent attempts to write events to GA in other activities will fail because the session has been stopped.

In addition, there's a bug in Google Analytics up through at least version 1.2 that causes it to keep a strong reference to the context you pass in to start(), preventing it from ever getting garbage collected after its destroyed. Depending on the size of your context, this can be a sizable memory leak.

The memory leak is easy enough to fix, it can be solved by calling start() using the Application instead of the activity instance itself. The docs should probably be updated to reflect this.

eg. from inside your Activity:

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

instead of

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

Regarding when to call start()/stop(), you can implement a sort of manual reference counting, incrementing a count for each call to Activity.onCreate() and decrementing for each onDestroy(), then calling GoogleAnalyticsTracker.stop() when the count reaches zero.

The new EasyTracker library from Google will take care of this for you.

Alternately, if you can't subclass the EasyTracker activities, you can implement this manually yourself in your own activity base class:

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 String apiKey;     protected Context context;      /**      * NOTE: you should use your Application context, not your Activity context, in order to avoid memory leaks.      */     protected GoogleAnalyticsSessionManager( String 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( String 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;     } } 
like image 156
emmby Avatar answered Sep 22 '22 02:09

emmby


The SDK now has a external library which takes care of all of this. Its called EasyTracker. You can just import it and extend the provided Activity or ListActivity, create a string resource with your code and you are done.

like image 31
sebastianf182 Avatar answered Sep 22 '22 02:09

sebastianf182