Using Google Analytics To Track Fragments

25,728

Solution 1

Mochini's answer uses Google Analytics V2. Bellow you can see how to do it on V4 and V3:

  • V4:

Application:

public class YourApplication extends Application
{
    public synchronized Tracker getTracker() {

        try {
            final GoogleAnalytics googleAnalytics = GoogleAnalytics.getInstance(this);
            return googleAnalytics.newTracker(R.xml.analytics);

        }catch(final Exception e){
            Log.e(TAG, "Failed to initialize Google Analytics V4");
        }

        return null;
    }
}

res/xml/analytics.xml (you can name it anything, it does not need to be called "analytics")

<?xml version="1.0" encoding="utf-8" ?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="TypographyDashes">

  <!--Replace placeholder ID with your tracking ID-->
  <string name="ga_trackingId">UA-XXXXXXXX-X</string>

  <!--Enable automatic activity tracking-->
  <bool name="ga_autoActivityTracking">true</bool>

  <!--Disable automatic exception tracking-->
  <bool name="ga_reportUncaughtExceptions">false</bool>

</resources>

build.gradle:

compile 'com.google.android.gms:play-services:7.3.0'

Fragment superclass:

public abstract class TrackedFragment extends Fragment{

    @Override
    public void onResume() {

        super.onResume();

        final Tracker tracker = yourApplicationInstance.getTracker();
        if(tracker != null){

            tracker.setScreenName(getClass().getSimpleName());
            tracker.send(new HitBuilders.ScreenViewBuilder().build());
        }
    }
}
  • V3

    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    
    import com.google.analytics.tracking.android.EasyTracker;
    import com.google.analytics.tracking.android.Fields;
    import com.google.analytics.tracking.android.MapBuilder;
    import com.google.analytics.tracking.android.Tracker;
    
    public abstract class TrackedFragment extends Fragment{
    
         private Tracker tracker;
    
         @Override
         public void onActivityCreated(final Bundle savedInstanceState) {
    
             super.onActivityCreated(savedInstanceState);
    
             this.tracker = EasyTracker.getInstance(getActivity());
         }
    
         @Override
         public void onResume() {
    
             super.onResume();
    
             this.tracker.set(Fields.SCREEN_NAME, getClass().getSimpleName());
             this.tracker.send( MapBuilder.createAppView().build() );
         }
    }
    

Source: https://developers.google.com/analytics/devguides/collection/android/v3/migration

Solution 2

This an example using FragmentActivity and fragments:

  1. Create XML file in value folder (values/analytics.xml):

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    
        <!-- Replace placeholder ID with your tracking ID -->
        <string name="ga_trackingId">XX-xxxxxxxx-x</string>
    
        <!-- Enable Activity tracking -->
        <bool name="ga_autoActivityTracking">true</bool>
    
        <!-- Enable debug -->
        <bool name="ga_debug">true</bool>
    
        <!-- The screen names that will appear in your reporting -->
        <string name="com.example.myapp.FragmentActivity">Fragment activity</string>
    
        <!--
            The inverval of time after all the collected data
            should be sent to the server, in seconds.
        -->
        <integer name="ga_dispatchPeriod">20</integer>
    
    </resources>
    
  2. In your FragmentActivity class, add this:

    @Override
    protected void onStart() {
        super.onStart();
        EasyTracker.getInstance().setContext(this.getBaseContext());
        EasyTracker.getInstance().activityStart(this); // Add this method
    }
    
    @Override
    protected void onStop() {
        super.onStop();
        EasyTracker.getInstance().activityStop(this); // Add this method
    }
    
  3. Create new class in your package: TrackedFragment.java

    public class TrackedFragment extends Fragment {
        private Tracker tracker;
        private String activityId;
        private String fragmentId;
    
        @Override
        public void onCreate(final Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            EasyTracker.getInstance().setContext(getActivity().getApplicationContext());
            this.tracker = EasyTracker.getTracker();
            this.fragmentId = getClass().getSimpleName();
            this.activityId = getActivity().getClass().getSimpleName();
        }
    
        @Override
        public void onResume() {
            super.onResume();
            this.tracker.sendView("/" + this.activityId + "/" + this.fragmentId);
        }
    }
    
  4. Finally, your fragment should extend from TrackedFragment like:

    public class NewFragment extends TrackedFragment {
    
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            return inflater.inflate(R.layout.newfragment, null);
        }
    
    }
    

Solution 3

Tracking methods section suggests that you just need to call EasyTracker.getInstance().setContext(getActivity()); first, then you can use the tracker in "other classes".

manual screen tracking section suggests that you can track a Fragment view with myTracker.sendView("Home Screen");

Solution 4

Another approach for V3 (since onResume() is tied to the Activity and not the Fragment. This works well when the parent/child relationships are well-known.

Parent Fragment sends initial event onStart():

public class ParentFragment extends Fragment {
    private Tracker mTracker;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        mTracker = EasyTracker.getInstance(getActivity());
    }

    @Override
    public void onStart() {
        super.onStart();

        mTracker.set(Fields.SCREEN_NAME, "Parent Fragment");
        mTracker.send(MapBuilder.createAppView().build());
    }
}

Child Fragment overrides both onStart() and onStop() :

public class ChildFragment extends Fragment {
    private Tracker mTracker;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        mTracker = EasyTracker.getInstance(getActivity());
    }

    @Override
    public void onStart() {
        super.onStart();

        mTracker.set(Fields.SCREEN_NAME, "Child Fragment");
        mTracker.send(MapBuilder.createAppView().build());
    }

    @Override
    public void onStop() {
        super.onStop();

        mTracker.set(Fields.SCREEN_NAME, "Parent Fragment");
        mTracker.send(MapBuilder.createAppView().build());
    }
}

Solution 5

Tiago's version can't be used in the new goole analytics v4. Instead, use this code from Google's docs

package com.google.android.apps.mobileplayground;

import com.google.android.apps.mobileplayground.AnalyticsSampleApp.TrackerName;
import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Tracker;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;

/**
 * Class to exercise Event hits.
 */
public class EventFragment extends Fragment {

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    View view = inflater.inflate(R.layout.event, container, false);

    setupEvent(view, R.id.video1Play, R.string.videoCategory, R.string.videoPlay, R.string.video1);
    setupEvent(view, R.id.video1Pause, R.string.videoCategory, R.string.videoPause,
        R.string.video1);
    setupEvent(view, R.id.video2Play, R.string.videoCategory, R.string.videoPlay, R.string.video2);
    setupEvent(view, R.id.video2Pause, R.string.videoCategory, R.string.videoPause,
        R.string.video2);

    setupEvent(view, R.id.book1View, R.string.bookCategory, R.string.bookView, R.string.book1);
    setupEvent(view, R.id.book1Share, R.string.bookCategory, R.string.bookShare, R.string.book1);

    final Button dispatchButton = (Button) view.findViewById(R.id.eventDispatch);
    dispatchButton.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        // Manually start a dispatch (Unnecessary if the tracker has a dispatch interval)
        GoogleAnalytics.getInstance(getActivity().getApplicationContext()).dispatchLocalHits();
      }
    });
    return view;
  }

  private void setupEvent(View v, int buttonId, final int categoryId, final int actionId,
      final int labelId) {
    final Button pageviewButton = (Button) v.findViewById(buttonId);
    pageviewButton.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
        // Get tracker.
        Tracker t = ((AnalyticsSampleApp) getActivity().getApplication()).getTracker(
            TrackerName.APP_TRACKER);
        // Build and send an Event.
        t.send(new HitBuilders.EventBuilder()
            .setCategory(getString(categoryId))
            .setAction(getString(actionId))
            .setLabel(getString(labelId))
            .build());
      }
    });
  }
}
Share:
25,728
Peter Djeneralovic
Author by

Peter Djeneralovic

Updated on June 18, 2020

Comments

  • Peter Djeneralovic
    Peter Djeneralovic about 4 years

    Just need to know the proper way to implement Google analytics to track when a user is on a fragment in real time this is what is do now

    @Override
    public void onResume() {
        super.onResume();
        Tracker myTracker = parentActivity.getTracker();
        myTracker.setCustomMetric(1, (long) 1);               
        myTracker.sendView("Music View"); 
    }
    

    the getTracker class is in my main activity and just returns the instance of tracker in the main activity

    Any help would be much appreciated!

  • Taranfx
    Taranfx over 10 years
    old API, Tiago's answer uses newer api
  • Kyle Ivey
    Kyle Ivey over 10 years
    getActivity() will return null in a fragment's onCreate(). Tracker setup should probably be done in onActivityCreated()
  • M.Sameer
    M.Sameer over 10 years
    What about onStop() or onPause() ? Do we need to inform GA that the screen is no longer active or will it know that when another one becomes active ?
  • Eric Woodruff
    Eric Woodruff over 10 years
    I think it would know. If you look at other answers below, it shows that they are tracking onStop as going back to the parent screen, which is probably not necessary as that screen has its own tracking.
  • iamreptar
    iamreptar about 10 years
    This code will overcount the number of times the user is on the Fragment. I would initialize the Tracker in onActivityCreate (cred: @KyleIvey). If your Fragment is using setRetainInstanceState(true), then I would take it a step further and use a global variable to keep you from sending the MapBuilder after orientation changes, switching apps, etc.
  • Sam
    Sam almost 10 years
    Is there any known way of doing this without using a subclass? e.g. for tracking activities you can use application's ActivityLifecycleCallbacks.
  • Bitcoin Cash - ADA enthusiast
    Bitcoin Cash - ADA enthusiast over 8 years
    @Sam You could use a dependency injection framework to inject the Tracker object, but you would have to do that in every Fragment of yours... I don't see a way around it.
  • Nick
    Nick over 7 years
    This approach (using onResume) will yield false data if you use fragments within a viewpager; your tracking events will fire on activity load all at once regardless of individual fragment visibility and will never fire again as the user moves back and forth through the fragments. Unfortunately, the suggested workaround of using setUserVisibileHint wont work outside of viewpagers so you'll gerally have to apply a solution on a fragment-by-fragment basis.
  • venkat
    venkat over 7 years
    simply superb!!!!! this is very good than google android docs... thanks to post this snippet.