Подтвердить что ты не робот

Google Analytics в приложении для Android - работа с несколькими действиями

Мне было очень приятно видеть, как легко настроить Google Analytics с моим приложением, но отсутствие документации у меня сидит с несколькими вопросами. Единственная информация, которую я могу найти, прямо из документации здесь, которая рассматривает только представление PageViews и Events из одного действия. Я хочу сообщать о видах страниц и событиях в нескольких действиях в моем приложении.

Прямо сейчас в onCreate() всех моих действий я звоню:

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

И в onDestroy() всех моих действий:

    tracker.stop();

Затем я отслеживаю страницы и события по мере необходимости и отправляю их вместе с другим запросом HTTP, который я выполняю. Но я не уверен, что это лучший способ. Должен ли я запускать start() и stop() в каждом действии, или мне нужно только вызвать start() и stop() в моей основной активности запуска?

4b9b3361

Ответ 1

Проблема с вызовом start()/stop() в каждом действии (по предложению Кристиана) заключается в том, что она приводит к новому "посещению" для каждого действия, к которому ведет ваш пользователь. Если это подходит для вашего использования, то это прекрасно, однако, это не так, как большинство людей ожидают, что посещения будут работать. Например, это очень затрудняет сравнение номеров Android с номерами в Интернете или iphone, поскольку "посещение" в Интернете и iphone сопоставляется с сеансом, а не с страницей/активностью.

Проблема с вызовом start()/stop() в вашем приложении заключается в том, что он приводит к неожиданно продолжительным посещениям, поскольку Android не дает никаких гарантий для прекращения действия приложения после закрытия последнего действия. Кроме того, если ваше приложение ничего не делает с уведомлениями или услугами, эти фоновые задачи могут запускать ваше приложение и приводить к посещениям "phantom". UPDATE: stefano правильно указывает, что onTerminate() никогда не вызывается на реальном устройстве, поэтому нет очевидного места для остановки вызова().

Проблема с вызовом start()/stop() в одном "основном" действии (как это было предложено Aurora) заключается в том, что нет гарантии, что активность будет действовать в течение всего времени, которое ваш пользователь использует для вашего приложения. Если "основная" активность уничтожается (скажем, чтобы освободить память), ваши последующие попытки записать события в GA в других действиях будут терпеть неудачу, потому что сеанс остановлен.

Кроме того, есть ошибка в Google Analytics, по крайней мере, с версией 1.2, которая заставляет его поддерживать сильную ссылку на контекст, который вы передаете, чтобы начать(), не позволяя ему получать мусор, собранный после его уничтожения. В зависимости от размера вашего контекста это может быть значительная утечка памяти.

Утечка памяти достаточно проста для исправления, ее можно решить, вызвав start(), используя приложение, а не сам экземпляр активности. docs, вероятно, должен быть обновлен, чтобы отразить это.

например. изнутри вашей деятельности:

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

вместо

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

Относительно того, когда нужно вызвать start()/stop(), вы можете реализовать своего рода подсчет ссылок вручную, увеличивая счетчик для каждого вызова Activity.onCreate() и уменьшая для каждого из них onDestroy(), а затем вызывая GoogleAnalyticsTracker.stop(), когда счетчик достигнет нуля.

Новая библиотека EasyTracker от Google позаботится об этом для вас.

В качестве альтернативы, если вы не можете подклассифицировать действия EasyTracker, вы можете реализовать это вручную самостоятельно в своем базовом классе активности:

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

Ответ 2

В SDK теперь есть внешняя библиотека, которая заботится обо всем этом. Его называют EasyTracker. Вы можете просто импортировать его и расширить предоставленную активность или ListActivity, создать строковый ресурс с вашим кодом, и все готово.

Ответ 3

Трекер будет отслеживать только те действия, которые он выполнил. Итак, почему бы вам не подклассы Activity, которые запускают его каждый раз на 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
}

Затем вы расширяете этот класс для каждого используемого вами действия:

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

Ответ 4

Подход, который я использую, заключается в использовании Bound Service (я, случается, использовал его уже, так что было спасено создание дополнительного кода котельной пластины.)

A Bound Service будет работать только до тех пор, пока есть связанные с ней действия. Все действия в моем приложении привязаны к этой службе, поэтому она длится только до тех пор, пока пользователь активно использует мое приложение - поэтому очень реальный сеанс.

Я запускаю трекер с экземпляром Singleton приложения, который я расширил, и добавил статический метод getInstance() для извлечения экземпляра:

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

Смотрите: http://developer.android.com/guide/topics/fundamentals/bound-services.html

Ответ 5

Я провел разное время между посещениями в моем приложении, работая вот так:

Я создал объект Singleer Tracker для оболочки для GoogleAnalyticsTracker, где я держу последний раз, когда что-то отслеживается. Если в этот раз больше х секунд, я рассматриваю его как новый визит.

Конечно, это полезно, только если вы отслеживаете все в своем приложении и, возможно, не лучшее решение в любой ситуации, хорошо работает для моего приложения.

Он поддерживает только TrackPageView, но setCustomVar и trackEvent должны быть легко реализованы.

В любом месте, где вам нужно отслеживать что-то, просто добавьте строку:

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

Я обычно делаю это в onResume активности

Отслеживание

Ответ 7

Интересно, может ли это быть сделано с помощью AOP.

Android может использовать только методы AOP для компиляции, поэтому, возможно, что-то вроде AspectJ?

Там немного больше информации об использовании AspectJ в Android в этой теме. Основная проблема заключается в том, что вам все равно нужно объявить о своих классах.