Snowplow Android Tracker 0.5.0 released


We are pleased to announce the release of the Snowplow Android Tracker version 0.5.0. The Tracker has undergone a series of performance improvements, plus the addition of client-side sessionization.

This release post will cover the following topics:

  1. Client-side sessionization
  2. Tracker performance
  3. Event building
  4. Other changes
  5. Demo app
  6. Documentation
  7. Getting help

1. Client-side sessionization

This release lets you add a new client_session context to each of your Snowplow events, allowing you to easily group events from a single user into a single session. This functionality can be activated by passing in the following builder commands to the Tracker creation step:

Tracker tracker = new Tracker.TrackerBuilder( ... ) .sessionContext(true) // To use the session context .sessionCheckInterval(10) // Checks every 10 seconds (default is 15) .foregroundTimeout(300) // Timeout after 5 minutes (default is 10) .backgroundTimeout(120) // Timeout after 2 minutes (default is 5) .build<span class="o">();

Once sessionization has been turned on several things will begin to happen:

  1. A client_session context will be appended to each event that is sent
  2. A polling check will be started to check whether or not the session has timed out
    • You can configure how often to check with the sessionCheckInterval method
    • If your app is in the foreground and no events have been sent for the foregroundTimeout period, the session will be updated and a new session started
    • There is a separate timeout if your application is detected to be in the background
  3. Each time the session information is updated it is stored locally in a private file which should persist for the life of the application
  4. Each time an event is sent from the Tracker, both timeouts for the session are reset

Session information should survive for the life of the application, i.e. until it is uninstalled from the Android device.

An important note here is that we cannot detect if the application is in the background or not from a library standpoint. You will have to update your applications onPause() and onResume() functions to manually flag this change. The following samples can be copied into an application activity to set the background state of the application for the session checker:

@Override protected void onPause() { super.onPause<span class="o">(); tracker.getSession().setIsBackground(true<span class="o">); } @Override protected void onResume() { super.onResume<span class="o">(); tracker.getSession().setIsBackground(false<span class="o">); }

If you know of a better way to detect this state in Android please let us know in the comments below!

2. Tracker performance

Several updates have been made to how the Tracker functions to improve performance and to reduce the memory footprint of the Tracker.

Firstly, events sent from the Tracker are now sent asynchronously over many threads as opposed to sequentially on a single background thread. This has drastically improved the speed at which the Tracker can send events to Snowplow collectors.

Secondly, we have also improved the speed at which events are added and removed from the local SQLite database by enabling writeAheadLogging. This means that we can now read and write to the database at the same time; this prevents contention between adding events to the outbound queue and emitting them to a collector.

This means the Tracker now processes as much as possible using a concurrent model, orchestrated by a configurable thread pool that you can define the size of:

Tracker tracker = new Tracker.TrackerBuilder( ... ) .threadCount(20) // A pool of 20 threads .build<span class="o">();

Note: the thread pool must be at least 2 in size due to the nature of the Emitter functioning as a singleton.

Please also note that if you make the thread pool too large it can have serious performance implications. An issue was discovered with using the RxJava default I/O scheduler in that it would grow the thread pool on demand, sometimes up to 500 threads, this in turn rendered the demonstration applications UI unresponsive and then subsequently crashed the application. See this ticket for more information.

Finally, we have also implemented an important fix to reduce the library’s memory footprint. We now nullify the large arrays of events fetched from the database for sending as soon as they are no longer required, allowing the Android garbage collector to work much more efficiently.

3. Event buildin

Alongside the performance updates we have made a fundamental change to how all the tracker.track functions operate. In place of many different types of track functions, we now have a single track function which can take different types of Events. These events are now built using the Builder pattern.

To illustrate lets look at how we were tracking a page view event in version 0.4.0:

tracker.trackPageView("", "example", ""<span class="o">);

For events like an Ecommerce Transaction it quickly becomes difficult to reason about:

TransactionItem item1 = new TransactionItem("item_id_1", "item_sku_1", 1.00, 1, "item_name", "item_category", "currency"<span class="o">); TransactionItem item2 = new TransactionItem("item_id_2", "item_sku_2", 1.00, 1, "item_name", "item_category", "currency"<span class="o">); List<TransactionItem> items = new ArrayList<>(); items.add(item1<span class="o">); items.add(item2<span class="o">); tracker.trackEcommerceTransaction("6a8078be", 300, "my_affiliate", 30, 10, "London", "Shoreditch", "Great Britain", "GBP", items<span class="o">);

Here is a page view in version 0.5.0:

tracker.track(PageView.builder() .pageUrl("pageUrl") .pageTitle("pageTitle") .referrer("pageReferrer") .build());

And here is the ecommerce event:

EcommerceTransactionItem item1 = EcommerceTransactionItem.builder() .itemId("item_id_1") .sku("item_sku_1") .price(1.00) .quantity(1) .name("item_name") .category("item_category") .currency("currency") .build<span class="o">(); EcommerceTransactionItem item2 = EcommerceTransactionItem.builder() .itemId("item_id_2") .sku("item_sku_2") .price(1.00) .quantity(1) .name("item_name") .category("item_category") .currency("currency") .build<span class="o">(); tracker.track(EcommerceTransaction.builder() .orderId("6a8078be") .totalValue(300.00) .affiliation("my_affiliate") .taxValue(30) .shipping(10) .city("Shoreditch") .state("London") .country("Great Britain") .currency("GBP") .items(item1, item2) // Simply put in any amount of items here! .build());

The new Builder pattern is slightly more verbose but the readbility is greatly improved. Also, you no longer have to pass in null entries for fields you don’t want to populate.

4. Other changes

We have also:

5. Demo app

The demonstration app has also undergone a few minor updates. We now have a radio button group which will allow you to switch of all data collection as noted in this ticket. Located under the Collection header, simply press ON or OFF to toggle this setting.

Under the Metrics header we now also deplay how many sessions the Tracker has observed; you can see that it will indeed survive application and phone restarts.

To get the latest version please download from here. To install the app you will need to allow installation from sources other than the Google Play Store.

6. Documentation

You can find the updated Android Tracker documentation on our wiki.

As part of this release we have updated our tutorials to help Android developers integrate the Tracker into their apps:

You can find the full release notes on GitHub as Snowplow Android Tracker v0.5.0 release.

7. Getting help

The Android Tracker is still a young project and we will be working hard with the community to improve it over the coming weeks and months; in the meantime, do please share any user feedback, feature requests or possible bugs.

For help on integrating the application please have a look at the setup and integration guides.

Feel free to get in touch or raise an issue in the Android Tracker’s issues on GitHub!


Related articles