web-dev-qa-db-de.com

Google Analytics in Android App - Umgang mit mehreren Aktivitäten

Ich war ziemlich aufgeregt zu sehen, wie einfach es ist, Google Analytics mit meiner App einzurichten, aber aufgrund der fehlenden Dokumentation muss ich einige Fragen beantworten. Die einzigen Informationen, die ich finden kann, sind direkt in der Dokumentation hier enthalten, die sich nur auf das Melden von PageViews und Ereignissen aus einer Aktivität bezieht. Ich möchte Seitenaufrufe und Ereignisse über mehrere Aktivitäten in meiner App melden.

Im Moment bei onCreate () aller meiner Aktivitäten rufe ich an:

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

Und im onDestroy () aller meiner Aktivitäten:

    tracker.stop();

Ich verfolge dann PageViews und Ereignisse nach Bedarf und versende sie zusammen mit einer anderen HTTP-Anforderung, die ich ausführte. Aber ich bin nicht so sicher, dass dies der beste Weg ist. Soll ich in jeder Aktivität start () und stop () aufrufen, oder sollte ich in meiner Hauptstartaktivität nur start () und stop () aufrufen?

45
Aurora

Das Problem beim Aufruf von start ()/stop () in jeder Aktivität (wie von Christian vorgeschlagen) ist, dass für jede Aktivität, zu der Ihr Benutzer navigiert, ein neuer "Besuch" erfolgt. Wenn dies für Ihre Verwendung in Ordnung ist, ist dies in Ordnung, aber die meisten Menschen erwarten nicht, dass Besuche zu arbeiten kommen. Dies würde beispielsweise den Vergleich von Android-Nummern mit Web- oder iPhone-Nummern sehr schwierig machen, da ein "Besuch" im Web und iPhone einer Sitzung und nicht einer Seite/Aktivität zugeordnet wird.

Das Problem beim Aufruf von start ()/stop () in Ihrer Anwendung ist, dass dies zu unerwartet langen Besuchen führt, da Android nicht garantiert, dass die Anwendung nach dem Schließen Ihrer letzten Aktivität beendet wird. Wenn Ihre App mit Benachrichtigungen oder Diensten arbeitet, können diese Hintergrundaufgaben Ihre App starten und zu "Phantombesuchen" führen. UPDATE: stefano weist richtig darauf hin, dass onTerminate () niemals auf einem realen Gerät aufgerufen wird. Es gibt also keinen offensichtlichen Ort, an dem der Aufruf auf stop () gesetzt werden kann.

Das Problem beim Aufruf von start ()/stop () in einer einzelnen "Hauptaktivität" (wie von Aurora vorgeschlagen) ist, dass es keine Garantie dafür gibt, dass die Aktivität so lange aufrechterhalten wird, wie der Benutzer Ihre App verwendet. Wenn die "Hauptaktivität" zerstört wird (beispielsweise um Speicherplatz freizugeben), schlagen Ihre nachfolgenden Versuche, Ereignisse in andere Aktivitäten in GA zu schreiben, fehl, da die Sitzung angehalten wurde.

Darüber hinaus gibt es in Google Analytics ab Version 1.2 einen Fehler, der dazu führt, dass es einen starken Verweis auf den Kontext enthält, den Sie zum Starten übergeben (). Dadurch wird verhindert, dass der Müll nach dessen Zerstörung gesammelt wird. Abhängig von der Größe Ihres Kontexts kann dies zu einem erheblichen Speicherverlust führen.

Das Speicherverlust lässt sich leicht beheben, es kann durch Aufruf von start () unter Verwendung der Anwendung anstelle der Aktivitätsinstanz selbst behoben werden. Die docs sollten wahrscheinlich entsprechend aktualisiert werden.

z.B. aus dem Inneren Ihrer Aktivität: 

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

anstatt

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

In Bezug auf den Aufruf von start ()/stop () können Sie eine Art manuelles Referenzzählen implementieren, indem Sie für jeden Aufruf von Activity.onCreate () einen Zähler erhöhen und für jedes onDestroy () dekrementieren und dann GoogleAnalyticsTracker.stop () aufrufen die Zählung erreicht null.

Die neue EasyTracker - Bibliothek von Google übernimmt dies für Sie.

Wenn Sie die EasyTracker-Aktivitäten nicht untergliedern können, können Sie dies alternativ manuell in Ihrer eigenen Aktivitätsbasisklasse implementieren:

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;
    }
}
78
emmby

Das SDK verfügt jetzt über eine externe Bibliothek, die sich um all dies kümmert. Es heißt EasyTracker. Sie können es einfach importieren und die bereitgestellte Activity oder ListActivity erweitern, eine String-Ressource mit Ihrem Code erstellen und fertig. 

17
sfratini

Der Tracker verfolgt nur die Aktivität, an der er ausgeführt wurde. Warum solltest du nicht eine Aktivität in eine Unterklasse unterteilen, die sie jedes Mal auf onCreate startet:

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
}

Dann erweitern Sie diese Klasse für jede Aktivität, die Sie verwenden:

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
    }
}
5
Cristian

Der Ansatz, den ich verwende, ist die Verwendung eines gebundenen Dienstes (ich verwende gerade einen Dienst, so dass die Erstellung eines zusätzlichen Boiler-Plattencodes erspart wurde.)

Ein gebundener Dienst ist nur so lange gültig, wie Aktivitäten daran gebunden sind. Alle Aktivitäten in meiner App sind an diesen Dienst gebunden, sodass er nur so lange dauert, wie der Benutzer meine Anwendung aktiv nutzt - daher eine echte "Sitzung".

Ich starte den Tracker mit einer Singleton-Instanz von Application, die ich erweitert habe, und fügte eine statische getInstance () - Methode hinzu, um die Instanz abzurufen: 

// 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();
}

Siehe: http://developer.Android.com/guide/topics/fundamentals/bound-services.html

1
evaneus

Ich habe eine zeitliche Trennung zwischen Besuchen in meiner App durchgeführt und folgendermaßen gearbeitet:

Ich habe ein Wrapper-Singleton-Tracker-Objekt für den GoogleAnalyticsTracker erstellt, in dem ich das letzte Mal, wenn etwas verfolgt wird, aufbewahre. Wenn diese Zeit mehr als x Sekunden beträgt, behandele ich sie als neuen Besuch.

Natürlich ist dies nur nützlich, wenn Sie alles in Ihrer App nachverfolgen und möglicherweise nicht in jeder Situation die beste Lösung sind. Dies funktioniert jedoch gut für meine App.

Es unterstützt nur trackPageView, aber setCustomVar und trackEvent sollten einfach implementiert werden.

Wo immer Sie etwas nachverfolgen müssen, fügen Sie einfach die Zeile hinzu:

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

Ich mache es normalerweise im onResume einer Aktivität

Tracker Gist

1
fasmide

Sie benötigen Folgendes: http://mufumbo.wordpress.com/2011/06/13/google-analytics-lags-on-Android-how-to-make-it-responsive/

Das ist auf der vorherigen Version und hat sehr gut funktioniert. Jetzt bin ich im gleichen Kampf wie Sie, da V2 nicht sehr konsistent zu sein scheint. 

1
Rafael Sanches

Ich frage mich, ob dies mit AOP möglich ist.

Android kann nur AOP-Methoden zur Kompilierung verwenden, also vielleicht etwas wie AspectJ?

Weitere Informationen zur Verwendung von AspectJ in Android finden Sie in diesem Thread . Das Hauptproblem ist, dass Sie immer noch Ihre eigenen Klassen deklarieren müssen.

0
Ben Neill