Booger
Booger

Reputation: 18725

Google Analytics V2 - IllegalStateException - can I initialize in onCreate() instead of onStart()

I am working with the new Google Analytics Beta for Mobile. I am getting the following exception sometimes when I run my code:

E/AndroidRuntime(29101): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.wsoft/com.wsoft.ui.AppActivity}: java.lang.IllegalStateException: You must call EasyTracker.getInstance().setContext(context) or startActivity(activity) before calling getTracker() E/AndroidRuntime(29101): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059) E/AndroidRuntime(29101): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084) E/AndroidRuntime(29101): at android.app.ActivityThread.access$600(ActivityThread.java:130) E/AndroidRuntime(29101): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195) E/AndroidRuntime(29101): at android.os.Handler.dispatchMessage(Handler.java:99) E/AndroidRuntime(29101): at android.os.Looper.loop(Looper.java:137) E/AndroidRuntime(29101): at android.app.ActivityThread.main(ActivityThread.java:4745) E/AndroidRuntime(29101): at java.lang.reflect.Method.invokeNative(Native Method) E/AndroidRuntime(29101): at java.lang.reflect.Method.invoke(Method.java:511) E/AndroidRuntime(29101): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) E/AndroidRuntime(29101): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) E/AndroidRuntime(29101): at dalvik.system.NativeStart.main(Native Method) E/AndroidRuntime(29101):

Caused by: java.lang.IllegalStateException: You must call EasyTracker.getInstance().setContext(context) or startActivity(activity) before calling getTracker() E/AndroidRuntime(29101): at com.google.analytics.tracking.android.EasyTracker.getTracker(EasyTracker.java:113) E/AndroidRuntime(29101): at com.wsoft.ui.AppActivity.setupApp(AppActivity.java:425) E/AndroidRuntime(29101): at com.wsoft.ui.AppActivity.onCreate(AppActivity.java:121)

To setup the analytics, I initialized the EasyTracker in the onStart() method (per documentation) like so:

public void onStart() {
        super.onStart();
        EasyTracker.getInstance().activityStart(this); 
    }

The IllegalStateException get's thrown out of code, that is executing in my onCreate() method - which of course gets run before onStart() - so I understand why this is being thrown.

I am thinking of moving the EasyTracker initialization inside the onCreate(), instead of onStart().

Any reasons why I shouldn't do this? Any suggestions on how to setup EasyTracker more reliable (in regards to Activity lifecycle? )

Or, if anyone has any good suggestions on how to ensure the EasyTracker is initialized before I use it (this causes a FC, which is obviously a bad thing.

Upvotes: 3

Views: 3360

Answers (4)

Kellvem Alves
Kellvem Alves

Reputation: 1

This will solve :P

public void onStart() {
        super.onStart();
        EasyTracker.getInstance(getApplicationContext()).activityStart(this); 
    }

Upvotes: 0

Martin Marconcini
Martin Marconcini

Reputation: 27246

Just as a reference, EasyTracker (in V2.x -deprecated library now-), calling setContext multiple time doesn't do anything, because internally the app does exactly this:

    public void setContext(Context ctx)
    {
        if(ctx == null)
        {
            Log.e("Context cannot be null");
        } else
        {
            ServiceManager sm = GAServiceManager.getInstance();
            setContext(ctx, ((ParameterLoader) (new ParameterLoaderImpl(ctx.getApplicationContext()))), GoogleAnalytics.getInstance(ctx.getApplicationContext()), sm);
        }
    }

The above method (which you are calling), calls this:

    void setContext(Context ctx, ParameterLoader parameterLoader, GoogleAnalytics ga, ServiceManager serviceManager)
    {
        if(ctx == null)
            Log.e("Context cannot be null");
        if(mContext == null)
        {
            mContext = ctx.getApplicationContext();
            mAnalyticsInstance = ga;
            mServiceManager = serviceManager;
            mParameterFetcher = parameterLoader;
            loadParameters();
        }
    }

Notice the mContext = ctx.getApplicationContext();?

So no matter what context you pass, you always get a reference to the same static Application context.

If you want to know more about the Context, be sure to read this excellent blog post:

The Android Context

Context is probably the most used element in Android applications…it may also be the most misused. Context objects are so common, and get passed around so frequently, it can be easy to create a situation you didn’t intend. Loading resources, launching a new Activity, obtaining a system service, getting internal file paths, and creating views all require a Context (and that’s not even getting started on the full list!) to accomplish the task. What I’d like to do is provide for you some insights on how Context works alongside some tips that will (hopefully) allow you to leverage it more effectively in your applications.

Upvotes: 0

guyland123
guyland123

Reputation: 841

Actually the docs say to initialize in onStart when you want to use Automatic Screen Tracking (EasyTracker), this is similar to the old V1 version of EasyTracker which did the same thing, but you would extend your class from a tracked version such as TrackedActivity. But the docs do state that if you are doing any manual screen tracking, that you make sure to call setContext before calling something like trackEvent. Docs are a little sparse with specifics on how to do this. Anyway, I just created my own trackEvent, and trackView classes, that take a context as a parameter, to make sure it is always set.

public static void trackView(Context ctx, String sScreenName){
    EasyTracker.getInstance().setContext(ctx);
    EasyTracker.getTracker().trackView(sScreenName);

}
public static void trackEvent(Context ctx, String sCategory, String sAction, String sLabel, Long lOptVal){
    EasyTracker.getInstance().setContext(ctx);
    EasyTracker.getTracker().trackEvent(sCategory, sAction, sLabel, lOptVal);
}

solves the problem for me. Hope this helps.

Upvotes: 6

Booger
Booger

Reputation: 18725

I did in fact change the initialization to happen inside the onCreate(), and seems to work great. So, to answer my own question, I do think this is a reasonable approach.

Upvotes: 0

Related Questions