Author: stevealbright

Google Analytics – Best Practice for Android

Google Analytics – Best Practice for Android

In this article, I dive deep into how I set up multiple Google Analytics trackers and most importantly, how I keep organized with what data I’m collecting.  Recently I have been more involved with statistical data, focusing on user flow and interaction.  Tracking one or two elements can be very clear on how to setup the data hierarchy. Once you move past the basics, planning and organization are the key ingredients to success.

Getting Starting

This article requires that you are familiar with the basic setup for Google Analytics on Android.  If not, please first go through Google’s documentation.  If you want to add code to your application as you read, you should take the time now to make sure the Android SDK and Google Play Services SDK is added to your project.  If you are still using a separate analytics library, I encourage you to review the latest documentation Google offers before continuing.

In some cases, you may want to use two trackers.  Whether you want the same data going two places or if you want to track data using two separate Analytics tracking id’s, below is the best way I found to setup and initialize multiple trackers.

First let’s setup some basic variables which should mostly be self explanatory.

Now lets add a enum used to identify trackers and define a HashMap to keep track of initialized trackers.  You may not see enums being used very much but I personally love how easy enums can be used and what they accomplish.  I highly suggest you read up on them if you never used them before.

Before we can start tracking we need to initialize an instance of Google Analytics.  If this is not done, your tracking will not work correctly and your app will error at runtime.

Take notice that I .setDryRun(GA_IS_DRY_RUN), which is using the static variable defined above.  This is a boolean that is manually set and controls whether or not actual data gets sent to the server.  If set to true, your tracking hits will only be logged.  You can also see how we set the log level based on the  GA_IS_DRY_RUN variable as well as the runtime build config.  It’s good practice to keep logging to the minimum when the build config is compiled as release.

Now that Google Analytics has an instance initialized, set whether or not this is a dry run and the log level configured… we now need an easy but efficient way to reference each tracker as needed.  For this, I setup a synchronized method.  By using a synchronized method I can get each tracker that I need with it being thread safe.  You can see that this is where the HashMap mTrackers that I set up comes into play.  Also, please notice the simple logic to set  CLIENT_PROPERTY_ID = null  while in debug mode.  This is a easy way to help prevent data corruption from unwanted data being sent to the live server.  Once data is sent to Google’s server, you can’t delete it.  Yes, you can filter or create a new Analytics property… but that is just a huge pain when it could easily be prevented.

Awesome!  If you have read to this point, we are close.  For convenience and sanity, I created multiple Application level methods that keep me organized and consistent.

EventBuilder

I create two methods for events HitBuilders.EventBuilder that I track.  The first method is used to only send the event to the global tracker and the second method is used to send the event to both the global and client tracker.  The last method is used by the first two methods to actually send the event to the server.  You can change this as needed to accommodate your specific analytics requirements.  In my case I have some Hits that I only want to send to the global tracker.  I also use some simple logic to NOT to send global tracking data if I am in a Debug build config.  Again, just an easy way to prevent your analytics data from being corrupted.  Please note in the source code I commented this out so I can collect real data for this tutorial.

IMPORTANT Subsequent fields need cleared after the event hit is sent. If you do not clear these fields, every hit thereafter will received unwanted data if you do not set them with new data prior. In the code above, we clear each subsequent field by setting it to null.

Event Screens - Google Analytics

So what is the deal with the subsequentParams?  It’s actually pretty simple.  I use the screen name and app title field to pass some extra data (if needed) for each event.  I recommend to at least send the screen name with each event that you track.  You can use custom dimensions and metrics but this requires a little more manual setup prior to implementation.  In my case I don’t want the burden to show every client how to enter custom fields on their Google Analytics.  This is very tedious due to the fact their indexes need to exactly match the data I am sending to each or it won’t make sense.  If you send custom field data to the server before you set them up the extra data passed would simply not be kept.

Google uses the Screen Name dimension in the events sub menu and is one of the easiest extra fields to see without extensive training.  I always think of who my audience will be to review the data.  Event – Screens are associated with each event and should not be confused with Screens.  I personally always try to use the same names for Event – Screens and Screens for screen tracking.  If you use different values, the data just looks more confusing and is especially harder to visualize in Behavior Flow.

Viewing the App Title field is not as obvious but you can easily view this data when creating a custom report or selecting this field as an extra dimension in the default Events – Overview.

ScreenViewBuilder

Similar to tracking events, screen views are also tracked by using the  HitBuilders class.  Below you will see that I only have two methods rather than three but they are very similar.  The first method is used to send a Screen Name to each Tracker and the second method is the one that actually sends the event to the server.

In most cases your screen names will be simple.  For example: Home, Details, Events or whatever depending on what kind of app you are working on.  In the app I am currently working on, Phandroid News, I use this structure plus some dynamic data for certain screens.  In the end you just want to make sure you can easily see and use the data that you are tracking.  Below is an example that uses some dynamic data and later in this article you will see it come to life with actual real data.

TimingBuilder

One last HitBuilders subclass that I would like to show you is the TimingBuilder.  I use this lots of different ways to find out where my code needs improved.  Reducing a few seconds or even just a fraction of a second here and there can go a long way which will improve the overall feel and flow of your application.  You want to be selective on what timed events you are logging so in the end you can understand what code is taking the longest.  If you connect and use data from multiple servers, this is a great way to see which server is faster to deliver results.

Before I get ahead of myself, lets first start with the application level code that is similar to the previous tracking methods that we already covered.

As you can see… this is very similar to what I already shown you.  So let’s move on.

Tracking a TimingBuilder is a little more complex than what I previously showed you.  With tracking timing you are responsible for keeping track of the start and stop time which will be used to get the elapse time (current time – start time).  Once you have this calculated elapse time you would then send the hit to the server similar to the way I showed you to send the previous tracking methods above. To make this a little more centralized, I have created a utilities class called TimeElapseUtils.  I hope by sharing this it makes it easier for everyone to track time events and saves you precious development time.

In this utility class I have an object called  TimeTrack.  I use this object to store all the necessary data into a Map for each time event that I want to track.  In the  trackStart(...) method I pass a String that is used as a key and a new TimeTrack object which initializes with timeUnit, category, name and label fields.  When initiated I automatically set the startTime based on the timeUnit type.  Since I store this  TimeTrack object into a Map I can then reference the data at the time I call  trackStopwhich sends the needed information to the application level code above.

Let me show you a simple example how this would be called.  This is an example of tracking the time of an AsyncTask.  Obviously this is just one of many app flows that you could track and it wouldn’t matter if it is synchronous or asynchronous.  Keep in mind that the main Analytics Tracker will always use background threads to process your Hits.

Simple, right?  You can use my utility class to start and stop when you need to and everything automagically happens for you.

So far we covered my advanced setup for Google Analytics, how I send data to multiple Trackers, most of the HitBuilders subclasses, along with brief examples on how the tracking data is being sent.  Now before we get into viewing the end results I need to reiterate my point at the very beginning of this article that organization is VERY important.

Organization

I wasted a lot of time going back and forth trying to make all my data that I am tracking align in one end result.  In short, I eventually created a spreadsheet.  Since I am such a nice guy, I am going to share with you my organization spreadsheet.  It’s nothing special but it will get you started right away and prevent you from wasting time with trying to create the perfect spreadsheet rather than what you should be doing which is… writing code!

Analytics Spreadsheet Template
Click to open on Google Drive

Take that spreadsheet, save a copy and expand it to your needs.  This will allow you to see an overview of everything you are tracking before you start implementing the code.  Trust me, you want consistent data being tracked or it won’t even be worth your time.  Make sure you do check out each tab at the bottom of the spreadsheet, which each tab is setup for each  HitBuilders class that I covered.  The spreadsheet has some data already entered that matches exactly to what the sample source code tracks.

Tracking Results

It’s always easiest to learn from real world examples and it’s important that I show you data from my real world project.  First let’s take a look at what this example application is sending to the server.  This will help you understand all of the examples that I have shown you in this article and help you understand what my code is doing in the projects source code.

Events Overview

Now this is very easy to see what is going on because I only have one category and one action.  The label here is the free form field that you type in and if you would have left it blank, it actually sends the String “Blank”.  The key is when you have multiple categories and multiple actions that don’t complement each other at each hierarchical level, you will become very frustrated when you can’t easily interpret all that precious data that you’ve collected.  I can’t stress enough to use the linked spreadsheet above!  Your future self will thank you :)

Google Analytics - Mobile Top Events

App Speed

In the example project I have code to randomly created the name of the event that is timed.  I also have code to generate a random time from 1000-3000 milliseconds so we can see some data that fluxuates.  A real world example that you will see later, will show you tracking app startup time separated by each process.  Once you figure out the problematic process from using time tracking, you could break it into more level to track each step in this process to determine which part of the code you need to improve.

Google Analytics - Mobile App Speed

Real World Analytics – Phandroid News

Testing example analytical data is always fun but let me show you some real data from one of my most recent apps that I been working on called, Phandroid News.  Our goal was to make this data easy to read for anyone, not just me, the developer.  Sure, I could have tracked events with more developer terms but then the data would only be useful to me.  It’s not only important to know what data you want to track but also who the audience is to review the collected data.  If your audience can’t interpret the analytical data that you collected — well — you just wasted your time.

NOTE  For each portion of data that you are are sending to the server, I recommend that you use defined Strings so you can easily keep the values consistent and avoid typos.  In order to keep these string from changing for each users language, make sure that you define these in donotranslate.xml.  Another approach would be to just define each somewhere as static final String.

Most of this data is obvious and you will be able to see everything clearly but one detail I want to elaborate on is the Screens data.  I not only used traditional screen naming like Home, Settings but also use article titles as dynamic text that goes along with the screen name.  For example: Article – <name of article>.  This allows me to easily use an advanced filter of search for ‘Article – ‘ and the results are wonderful.  We can now see top opened articles from our mobile app.  This is just one example of many ways to track data but you need to find the best for your application.  

Realtime Overview

Google Analytics - Realtime Overview [Phandroid News]

App Speed

Google Analytics - App Speed [Phandroid News]

Behavior Flow

Google Analytics - Behavior Flow [Phandroid News]

App Overview

Google Analytics - App Overview [Phandroid News]

Screens

Google Analytics - Screens [Phandroid News]

Custom Dashboard

Google Analytics - Custom Dashboard [Phandroid News]

In summary I showed you the best practice for setting up an advanced Google Analytics tracking configuration. Below you will see the code for this tutorial, which is a nice and neat sample project hosted on GitHub. As I did not covered every HitBuilders subclass, I did however give you enough insight to connect the dots. I do look to expand this code in the near future and like always, I will document my work here. Thanks for reading and I hope that you have found this Analytics information useful!

https://github.com/codeversed/analytics-example

Float Frame Layout Example

Android App Polishing – FloatFrameLayout is a Simple way to Polish Android Apps

A couple of weeks ago, Chril Mottier posted some neat animation examples on how he polished his current Android project Capitaine Train.  A little after this Chris Banes shared a gist with example code on how to do this exact effect.  Apparently this is Chril’s code but for some odd reason he couldn’t share it?

 

Floating Label Layout Example

This code inspired me to create another example for app polishing called FloatFrameLayout.  The concept is based off of how FloatLabelLayout was created so if you understand that code, this will be super easy for you.  If both are new from you, no problem… you should be able to use this code very easy.  This example is just one little way of using this code but could be used for Android App Polishing for any views of choice!  Code could easily be tweaked to something different as well.

 

Float Frame Layout Example

Example Layout

The main idea behind these examples is how the views are added to the window.  Here is how FloatFrameLayout calls the animation frames:

FloatFrameLayout’s addView

Take note that when I addView I search the child’s parent to see if its a LinearLayout.  This is so inside the frame you can group multiple views (TextView’s for example) and have them animated together.  Each child view will animate one after another to provide a nice “friction free” animation effect.

The animation effect itself is a slide and fade animated together using nine old android library for backwards compatibility.  I created some attributes so you can control the duration of the slide and fade seratally.  By default I have the slide set to 1000 and the fade to 900.  Slightly different values here provides a smoother transition IMO.

Attributes to Modify

Animation Code

Even if you don’t use this particular example you may be able to at least get something out of the animation code itself.  Here is an example of using multiple ObjectAnimator’s and in my case, which use nine old androids from Jake Wharton

 

If you need anything more explained please comment below and I would be more than happy to expand the post in more detail.  As always you can Fork Me and grab the full code example.  Extra bonus I provided the inspiration project that is from Chyril Motter’s code.  Please do yourself a favor and check out his personal blog too!  It’s a fabulous resource of knowledge.

FloatFrameLayout

https://github.com/srafx/floatframelayout

FloatLabelLayout

https://github.com/srafx/floatlabellayout

Big Picture Expandable Notifications for Android

Expandable Notifications for Android – Examples and Source

Expandable Notifications

Jelly Bean we not have the ability to provide more functionality such as expandable notifications and actions buttons.  We can use the rich styles provided or even create our own custom style for our expandable notifications.  This gives us the flexibility in both size and layout to create the perfect expandable notifications.

NotificationManager

Android Notifications are created by the Notification class.  Before you utilize the Notification class you first need to declare NotificationManager to be able to get the proper Context from the activity or service depending on your application setup.

Builder classes

Notification.Builder – This class was added in Android 3.0 Honeycomb [API 11].  So if you need to support older SDK’s you will need to use NotificationCompact instead.

NotificationCompat.Builder – This class is in the version 4 Support Library (compatible Android 1.6 and up).

The NotificationCompact.Builder, similar to other class builders, provides an interface that is used to create a Notification object. You use a PendingIntent to specify the intent action which should be shown when the user is notified.  The PendingIntent will be used almost like a token,  passed to the builder using setContentIntent. If you are in need of some extra actions, like the archive button in gmail notificaitons, you can specify three of these action buttons by using the builders addAction.  Once you have the notification built, the next step you will see how it is called.

In Android 3.0 the app navigation using the back key changed.  You can read more about this here in the TaskStackBuilder Class Overview.  This Class was not introduced until API 16 so if you do implement this recommended convention for the back key

make sure you use the TaskStackBuilder located in the Support Library.  This will ensure you have backwards capability for constructing synthetic back stacks for cross-task navigation on Android 3.0 and newer.

Notification views

Normal View – A notification in normal view appears in an area that’s up to 64 dp tall. Even if you create a notification with a big view style, it will appear in normal view until it’s expanded.

  1. Content title
  2. Large icon
  3. Content text
  4. Content info
  5. Small icon
  6. Notification time

Big View – A notification’s big view appears only when the notification is expanded, which happens when the notification is at the top of the notification drawer, or when the user expands the notification with a gesture.  Expanded notifications were first introduced in Android 4.1 JellyBean [API 16].  Expandable notifications were designed to support rich notification style objects called Notification.Style.

  1. Details area

Creating Notifications

Normal View

One point to remember is that all notification objects, including a Normal View, are required to have a small icon, a title, and detail text.

Normal Notification for Android

Big View

You will use this style the most when setting up expandable notifications.  This Notification.Style class contains three direct subclasses which are:

  1. Big Text Style – Displays a large text block to show the user more details on the item at hand.
  2. Big Picture Style – Displays a bitmap up to 256 dp tall similar to a screenshot notification.
  3. Inbox Style – Displays rows of text like a listView similar to the Gmail notification for multiple emails.

To apply a rich notification style to the notification, you first need to create the style object itself.  For this example I am showing you the BigPictureStyle subclass.

Big Picture Expandable Notifications for Android

 

Custom View

So what if the rich notification styles don’t provide you with the layout you need?  Easy, just create your own layout and pass it to the builder.  One little fact to retain is that notifications use remote views, which means you need to create a layout using a RemoteView.  Below is exactly how you would need to create this custom RemoteView.  When using a custom view, it will still function like the other expandable notifications we talked about.

First you need to create your layout file, here is one for an example.

Next create the RemoteView that uses your custom layout and apply it RemoteView using bigContentView.

Custom View Expandable Notifications for Android

 

Source Code

https://github.com/srafx/Notifications

Odexed vs. Deodexed

Deodexed vs Odexed – The Important Differences Explained.

Before I go into explaining the difference between deodexed and odexed, let’s first make sure you understand the common file format definitions.  If you want the simple answer, see the summary in this post.

Related Vocab

term definition
.dex Android programs are compiled into .dex (Dalvik Executable) files, which are in turn zipped into a single.apk file on the device. .dex files can be created by automatically translating compiled applications written in the Java programming language.
.odex An .odex file is an Optimized .dex file, which is basically a pre-compiled app for a specific device platform.  A .odex is essentially a .dex that has been optimized by dexopt.
.apk Android application package file (APK) is the file format used to distribute and install application software and middleware onto Google's Android operating system; very similar to an MSI package in Windows or a Deb package in Debian-based operating systems like Ubuntu. To make an APK file, a program for Android is first compiled, and then all of its parts are packaged into one file. An APK file contains all of that program's code (such as .dex files), resources, assets, certificates, and manifest file. As is the case with many file formats, APK files can have any name needed, provided that the file name ends in .apk.
zipalign An archive alignment tool that provides important optimization to Android application (.apk) files.  Full definition and usage: zipalign | Android Developers

Odexed and Deodexed

A standard ROM is supposed to be odexed for release which provides smoother and faster loading of apps into memory.  Each .apk has a corresponding .odex.  When the application is used by either the system or the user, the .odex is used to start loading the app.  A ROM that is deodexed has only the .apk file.  When the application is called into memory from only pulling the data from it’s .apk, this takes longer due to not being optimized for easier retrieval from the system.

Common questions that I get asked way too often are:

  1. Why do custom ROM’s deodexed?
  2. Should I use a odexed or a deodexed ROM?

To answer these questions it comes down to one word, themability.  If you talk to anyone that themes ROM’s they will tell you that it’s extremely easier to theme a deodexed ROM.  Since we started using deodexed ROM’s, themers could now create themes to apply to a ROM rather than the tedious option to theme the ROM itself (release a custom ROM for a theme).  If you use a odexed ROM and try to apply themes, it will not work or only theme some visual aspects, which will give you a terrible user interface to experience.

Deodex Cons

I bet you are now wondering why… why is there even an option to download a custom ROM that is odexed?  The answer to that is speed.  Remember how I said that odexed files are optimized for easier retrieval?  Simply put… it’s optimized (like indexing a data table) so the system can open the .apk faster.

Deodex and zipalign

Everyone wanted the best of both worlds so quickly after the deodexed trend started to peak, these savvy ROM developers came up with a solution to zipalign at boot.  This optimizes each .apk on every reboot which then allows the system to access applications more efficiently and most importantly, faster.  Of course, the disadvantage is slightly slower boot times.

Summary

If you have a choice to download the custom ROM odexed or deodexed, I would just go with the deodex ROM.  You never know when you would want to try out a theme or do some modifications yourself and it’s nice to have easy options rather than flashing a whole new ROM.  With newer devices you may not even see a noticeable difference to zipalign on boot.  If your device is pretty slow and outdated, well then I would suggest to think about this a little harder.  I would bet some of you would prefer to get a nice minimal optimized (odexed) ROM for better performance and speed over customizing the user interface.