我很高兴看到使用我的应用程序设置Google Analytics是多么容易,但缺少文档让我有几个问题。我能找到的唯一信息就是文档here,它只关注从一个Activity报告PageViews和Events。我想在我的应用程序中跨多个活动报告PageViews和事件。
现在,在我所有活动的onCreate()中,我打电话给:
tracker = GoogleAnalyticsTracker.getInstance();
tracker.start("UA-xxxxxxxxx", this);
在我所有活动的onDestroy()中:
tracker.stop();
然后我根据需要跟踪PageViews和事件,并将它们与我正在执行的另一个HTTP请求一起发送。但我不太确定这是最好的方法。我应该在每个活动中调用start()和stop(),还是应该只在主启动器活动中调用start()和stop()?
答案 0 :(得分:79)
在每个活动中调用start()/ stop()的问题(如Christian所建议的)是,它会导致用户导航到的每个活动都有一个新的“访问”。如果这对您的使用没有问题,那么这很好,但是,这并不是大多数人期望访问工作的方式。例如,这会使得Android号码与网络或iPhone号码的比较非常困难,因为网络上的“访问”和iphone映射到会话,而不是页面/活动。
在您的应用程序中调用start()/ stop()的问题是它会导致意外长时间访问,因为Android不保证在您上次活动关闭后终止应用程序。此外,如果您的应用对通知或服务执行任何操作,这些后台任务可以启动您的应用并导致“幻影”访问。 更新:stefano正确指出onTerminate()永远不会在真实设备上调用,因此没有明显的地方可以将调用置于停止()。
在单个“主”活动中调用start()/ stop()的问题(如Aurora所建议的)是,无法保证活动会在用户使用您的应用程序期间保持活动状态。如果“主”活动被销毁(比如释放内存),那么随后尝试在其他活动中向GA写入事件将会失败,因为会话已经停止。
此外,至少版本1.2中的Google Analytics中存在一个错误,导致它对您传递给start()的上下文保持强引用,从而防止它在被破坏后被垃圾收集。根据您的上下文的大小,这可能是一个相当大的内存泄漏。
内存泄漏很容易修复,可以通过使用Application而不是activity实例本身调用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 ()当计数达到零时。
来自Google的新EasyTracker库将为您解决此问题。
或者,如果您不能将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;
}
}
答案 1 :(得分:17)
SDK现在有一个外部库来处理所有这些。它叫做EasyTracker。您只需导入它并扩展提供的Activity或ListActivity,使用您的代码创建字符串资源即可完成。
答案 2 :(得分:5)
跟踪器只会跟踪执行它的活动。那么,为什么不对每次在onCreate
上启动它的Activity进行子类化:
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
}
}
答案 3 :(得分:1)
我使用的方法是使用绑定服务(我恰好使用了一个绑定服务,因此可以节省额外的锅炉板代码的创建。)
绑定服务只会在绑定了活动时才会持续。我的应用程序中的所有活动都绑定到此服务,因此只要用户正在使用我的应用程序,它就会持续 - 因此非常真实的“会话”。
我使用Application的单例实例启动跟踪器,我已经扩展并添加了一个静态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
答案 4 :(得分:1)
我在我的应用中进行了基于时间的分割,工作方式如下:
我为GoogleAnalyticsTracker构建了一个包装器单件跟踪器对象,我保留了最后一次跟踪的内容。如果那个时间超过x秒我将其视为新访问。
当然,这只有在您跟踪应用中的所有内容时才有用,并且在某些情况下可能不是最佳解决方案,但对我的应用效果很好。
它只支持trackPageView,但是应该可以轻松实现setCustomVar和trackEvent。
您需要跟踪某些内容的任何地方只需添加以下行:
Tracker.getInstance(getApplicationContext()).trackPageView("/HelloPage");
我通常在活动的onResume中执行此操作
答案 5 :(得分:1)
你需要这样的东西:http://mufumbo.wordpress.com/2011/06/13/google-analytics-lags-on-android-how-to-make-it-responsive/
这是以前的版本并且过去非常好用。现在我和你一样挣扎,因为V2似乎不是很一致。
答案 6 :(得分:0)
我想知道这是否可以使用AOP完成。
Android只能使用编译时AOP方法,所以可能像AspectJ?
在this thread中有关于在Android中使用AspectJ的更多信息。主要问题是您仍然需要在您拥有的类上声明。