It Ships. It’s Profitable. It’s Important.

Like it or not, we all have favorites and this rings true even in technology. Some people love JavaScript, Node and AngularJS and some people love Ruby on Rails and some people love to use Java with Spring and some people love .NET with ASP.NET MVC … etc … etc … etc … you get the point. Furthermore, some people love the hot new distributed architecture pattern, some people love the MVC pattern and some people love the spaghetti code pattern (if we can even call it that) again, … you get the point. People use what they like and/or know how to use and they get to decide what they like, and that’s OK. We can use anything to get the job done, and if it solves the problem then we can usually move onto the next issue at hand, regardless of the technology, practice or pattern.

Unfortunately, I’ve noticed a lot of people spewing nonsense about certain technology stacks/platforms/frameworks/etc. Using a given technology or stack or language or framework/etc is up to you, but hating on any given technology (and its adopters) gets you nowhere.

Furthermore, if the ridiculed technology is in production and is making money then it’s far better than whatever is sitting in your private project repo that has not even shipped yet. That’s a fact. Even if you wrote something and it is profitable and it’s in a different language, who cares? It works, it shipped and now you’re onto the next thing. No need to ridicule anyone about how your technology is better. I tell you what – higher level CEO’s rarely care that their system is written in Rails or Python or .NET. You know what they care about? Being profitable. Keeping people employed, motivated and happy. Growing the business. That’s what they are about. Technology is a tool.

Time for a story …

About 7 years ago I was working at a small insurance company in Minnesota. The client had a large application that helped managed specialty insurance policies/claims/etc for a large non-tech industry. Long story short – the app was a disaster and was written in a language I did not care for, but I did know how to work with. In my opinion, the application was poorly architected but it worked. The first glimmer of “WTFness” I encountered was when I had to add a single item to a drop down list. This took two full days. This is unacceptable in any technology. After about a month on the project, I was ready to give up due to frustration. I could not take it anymore I provided some unsolicited advice to one of the architects on the project. I said that the system needs to be put on life support and needs to be re-written because they’re throwing money out the window on small improvements and the project will literally drag on FOREVER. A rewrite of the system or its subcomponents might be a better option. What I didn’t see coming is what hit me the hardest. When he replied, he changed my career, and in turn he also changed my life because it altered the way I approached technology problems from that day forward.

He said something very similar to this …

“Donn, this app generates over 6 million dollars a month for the company. Without this app and us improving it, none of us in these buildings would have a job. The reason we are updating this app is because it is what keeps us employed and it is what keeps the company moving forward. We don’t have time to re-write it. Without this app, we have nothing. With it, we have 6M a month. Sure it was sub-optimally designed at first, but that’s all we could do at the time given our limited resources. Now, we have money to spend on fixing it and improving it incrementally. We have money to hire smart consultants and that is the reason we can afford to have you here. We have to fix it, we have to improve it, because now, we have the money to do so. It is what it is. It may not be fun, but it has to be done.”

That conversation was very humbling and to this day it’s something that resonates with me with every technology conversation that crosses my path.

It did not matter that the app was written in a  language I did not like, used patterns that were bad in practice and was difficult to update. It was profitable.

The app was written in the best way possible at the time with the best tools available to those who were knowledgeable at the time. Sure, they may have made some mistakes and did things wrong or skimped in certain areas, but at that time it didn’t matter. They were trying to make a profitable product. Now they have one and it’s making enough money to bring in the proper talent to fix these pain points.

I’ve seen this same scenario replay itself over a dozen times in the last many years (and this happens a lot at startups in the Silicon Valley), but now when I recognize it I don’t carry any sort of spite for a given technology/language/pattern/practice/etc. I realize that this product was written with a particular goal in mind with a particular budget and time frame and most likely they had limited or no budget, a very short time frame and a very small staff when the app started. I’ve also seen this same story replay itself at the enterprise scale. Just because there are 5000 people at a company doesn’t mean that areas of the company do not work in silos. When it happens we have to look at it objectively and say: “It is what it is, but now how do we improve it.”

The thing is … Times change, languages change, frameworks change, best practices change and overall – technology as a whole … changes. This is a good thing, but as professionals we have to recognize when the right time to evaluate and implement a new technology is. We should not come in and bad mouth a particular technology because we don’t like it or approve of it.

We’ve all run into it as well … for example – Perhaps a client’s system is simply too slow with PHP and MySQL and we need more scale to grow the business. Perhaps the app is written in a way we cannot horizontally scale (this happens a lot). Maybe the app is slow because there are no indexes on the MySQL database. Already implemented those indexes and the app is still slow? Already fixed all the areas you can? Then at that time it might be time to evaluate NodeJS or Go or something else. So be it. There is nothing wrong with that. Just don’t throw the baby out with the bathwater simply because the bath water is murky. Realize what you and your client have and evolve. Use the right tool for the right job.

Regardless what it is, regardless how it’s written, regardless how it’s architected, regardless how it’s built, regardless how it’s deployed …

We’re professionals and we have to objectively look at each project with a fresh perspective in order to help move the client forward in the right direction regardless of the technology at hand.

It’s hard to determine when something is worth fixing, improving and redesigning vs starting afresh. It’s hard because sometimes in language X or technology Y solving this same problem would be 10x easier. This is when most of us get easily frustrated. This is the time when we need to sit back and evaluate the situation. When I get in the weeds and start over-analyzing a project I have to remind myself of this simple principle:

If its ships and it’s profitable – then it’s important.

While this may not solve your problem, it will help reset your expectations on said technology and align your current goals to that of the business you’re helping.

Android Studio Espresso 2.0 ClassNotFoundException

File this under “I’m writing this so when I Google for it in 6 months, it pops up”. 

 

I recently set up an existing Android project with Espresso 2.0 and immediately stared running into this error when I ran the tests: 

Running tests
Test running started
Test running failed: Instrumentation run failed due to 'java.lang.ClassNotFoundException'
Empty test suite.

I spent some time last night fighting this error and then I figured out the solution this morning.

The problem is that I’m using Dagger in this project and Espresso 2.0 also uses Dagger (see Espresso Dependencies). The core problem is that the ‘javax.inject’ dependency was borking the test run. 

How to to Fix

Change this

androidTestCompile('com.android.support.test.espresso:espresso-core:2.0')

to this: 

androidTestCompile('com.android.support.test.espresso:espresso-core:2.0') {
   exclude group: 'javax.inject'
}

 

Problem solved. 

Diff Before Commit

Last week I tweeted something that got some conversations going:

The tweet itself was not a huge novel concept and it’s something that many quality devs do every single day, many times a day. Unfortunately its also something that the majority of folks do not do. Jake expressed his beliefe that this should happen as well in this humorous reply:

 

Well then … Why is reviewing your code before committing (or a code review) important?

Reviewing your code is important because you’re going to catch something you forgot to add, remove or you will see an error in your ways and you’ll fix it before you push the commit it to the server. I can’t tell you how many times (I’m talking thousands upon thousands of times) I’ve caught some invalid code during a pre-commit diff.

How many times have you accidentally pushed that code that had some old debug tracing or a red background color? Probably more than you can remember. It happens to all of us.

How To

The simplest way is to do it via the command line if you don’t use a diff tool or an IDE that supports it. I use git, here’s the command to show an inline diff in the command line interface:

git diff

or with the path to the file you’re interested in (if many file are modified)

git diff /path/to/file

If you have a difftool installed you can issue the following command:

git difftool

or with path to the the file you’re interested in (if many files are modified)

git difftool /path/to/file

With an IDEA IDE (Android Studio, WebStorm, IntelliJ, PyCharm, RubyMine, and more)

You can right click on the file in the editor and select git —> Compare with Same Repository Version and you’ll get the screen below:

Users donnfelker Documents android bootstrap source android bootstrap app src main java com donnfelker android bootstrap ui BootstrapFragmentActivity java

Using a HotKey

Personally, I avoid using the mouse at all times so I’ve set up a shortcut in all my IDEA based IDE’s. Here’s how to do that:

I’m using Android Studio here, but the process is the same for other IDEA IDE’s.

Open the Preferences:

prefs

Next in the filter, type “keymap”, you’ll see the items the filter below narrow down to simply “Keymap”

Banners and Alerts and Preferences and values v21 theme xml app android bootstrap Documents android bootstrap source android bootstrap Android Studio Beta 0 8 14

In the search box type “compare with” to filter the list of keymap options.

Preferences and values v21 theme xml app android bootstrap Documents android bootstrap source android bootstrap Android Studio Beta 0 8 14

Next right click on the “Compare with the same Repository Version” under your VCS. I’m using Git below.

Preferences and values v21 theme xml app android bootstrap Documents android bootstrap source android bootstrap Android Studio Beta 0 8 14

Now your cursor will be in the “First Stroke” box. I chose “Shift + CMD + D” for my hot key for this command. Simply press those three buttons at the same time “SHIFT + CMD + D” and the values will fill themselves in for you in the “First Stroke” box. You’ll notice at the bottom of this dialog you will show you any other key combos conflict with this key combination. In this case, there are no conflicts. Click “Ok” and and click “Ok” on the parent Preferences window and you’ll be back at your IDE.

Enter Keyboard Shortcut and Preferences

Now go back to your file, make a change, and hit “SHIFT + CMD + D” and you’re diff window will show up automatically. :)

Users donnfelker Documents android bootstrap source android bootstrap app src main java com donnfelker android bootstrap ui BootstrapFragmentActivity java

This can be done with any IDEA IDE, so have fun. Other IDE’s like Visual Studio, etc also have similar features, you’ll just have to hunt them out.

Enjoy!

Three of the Best Audio Purchases I’ve Ever Made

When I used to run a record label I got really into audio products. Almost to the point of being a full blown Audiophile. I did gain some valuable insight in to the world of audio from my experience. I now respect quality sound. Nice deep bass, proper treble that isn’t “tinny” and overall a product that is visual appealing is usually the icing on the cake. Though I may enjoy quality sound there’s no way in hell I’m going to spend thousands of dollars on a speaker for general listening. That in mind, here are a few purchases I’ve made over the last three years that have literally changed my audio consumption habits and boosted my audio listening pleasure immensely. 

 

JVC HAFX1X Xtreme Xplosives in Ear Earbuds – $28 

 

JVC XTreme

I did a lot of research into ear buds and headphones. I needed a portable pair of great sounding earbuds/headphones for when I work at a coworking location, in a coffee shop or when the kids are just bouncing off the walls in my  house (while I work in my home office). I originally looked up the Beats by Dre headphones and earbuds but found that after some digging the quality of the headphones for the price is an absolute rip off. Long story short – Beats by Dre headphone and earbuds are WAYYYY over priced and overhyped. Unfortunately the mass market has bought into them and they’re super popular.

The problem I have with earbuds in general is that they can get lost easily and I’m not about to spend $100+ dollars on some headphones or earbuds I may end up losing. I found these JVC’s and tried them out. Whoa. Super impressed for around $28 dollars. I like these earbuds so much that I bought two more pair and stuffed them into my closet in case they stopped making them (so I had some back ups when these wore out). 

From music to conference calls (there is no inline mic, so I’m using my MacBooks mic) and everything in between these sound great in all areas. I recommend them to everyone who looking for a pair of cheap headphones, especially for teenage children who seem to lose everything. :) 

 

 

Bose SoundLink Mini Bluetooth Speaker – $199

Bose SoundLink Mini

 

I’ll be honest, I had a very hard time purchasing this. To me, $199 for a blue tooth speaker is insane. But I did a bunch of research and found that this thing out performs the Jambox and many others in the same price range. I decided to close my eyes and click the purchase button. I’m glad I did. The Bose SoundLink Mini unit sits on a charging doc (when in use or not) so its always charged when I need it. I just pick it up and move it when I need it and put it back – no plugging in cords/etc. While thats not a huge deal, its a huge convenience and I’ve never seen it without power since I’ve had it. How many times have you forgot to plug something in? Yeah… exactly. Not with this thing, put it down and its charging on the dock.

I use this thing while at my desk to listen to podcasts from my phone, books from Audible and various other things. While at clients or in a meeting I can pull it out and put it on the table and now we have a instant conference call speaker through my phone with the SoundLink Mini. Awesome. I also use it for when we go out in the back and go swimming in the pool. Bring it out, put on some music and just relax. I’ve been in the backyard swimming and enjoying family time for over 6 hours without this thing going dead. 

The sound quality is superb and I’m very happy with this purchase. 

 

 

Sonos Play 5 – $399

Sonos Play 5 

Cant leave out the Sonos. Great for the home, office or anywhere with an always on internet connection. This is another one I had a hard time buying because of the price. However, a co-working spot I used to frequent had one and I fell in love with it so I decided to pick one up for my family. My wife nearly wanted to strangle me after buying this but very soon after she fell in love with it and now she can’t live without it. I think she likes it more than I do. :)

We play radio stations through TuneIn or IHeartRadio and use music services such as Pandora, Sirius/XM, Google Music, Spotify, etc. You name it, they have it, or its in their “Labs” area. Its fantastic. We put it on top of our refrigerator and we listen to music all the time. I may end up picking up a Sonos 1 for the master bedroom/bathroom soon because we love it so much. 

 

 

There you have it, those are my top three audio purchases over the last few years. I use all of these devices daily and if you’re looking for something to up your audio consumption quality, check out one of the items above. 

Why I Use Crashlytics – Part 2

Why I Use Crashlytics Part 2

In Part 1, I discussed how to set up Crashlytics to get intricate data about the crashes, devices, and how to easily view this data from within Android Studio. In this article I’m going to discuss how this data can help you fix the most critical crashes with minimal effort and create happy users and customers for your business. I’ll also talk about how I use Crashlytics in an application that is very large in scale.

 

The Beauty is in the Details

 

One of the great things about Crashlytics is the level of detail you’re given when a crash occurs. As a product manager, dev lead or engineer you’re able to quickly assess the risk the crash poses to your overall install base. With the device and operating system breakdown you can determine if a particular crash is only occurring on Android 2.x or everywhere (or another version). You can determine if the crash is affecting only a particular device manufacturer. This is a tremendous help.

 

One of the things I’ve done with my clients to help assess the risk of a particular issue is to juxtapose the issue statistics vs. the statistics from Answers by Crashlytics, Crashlytics’ new mobile analytics service (as shown below). Using this information I can determine if the majority of my users are exposed to this issue simply by looking the users count from Crashlytics’ crash reporting as well as the daily active users count for the OS version and the daily active users count for device from Answers. This data will provides me with the insight to determine if the issue is severe or just an edge case that is rarely hit (the issue count really helps here and is covered in the next section in more detail).

 

A sample screenshot of Answers by Crashlytics providing the Daily Active Users by Operating System (OS).

 

 

A sample screenshot of Daily Active Users by Device Type.

 

These charts provide tons of great info that you can compare to the issues in Crashlytics. If your app is generating an error occasionally it’s easy to determine what to fix, how to fix it, and when to fix the issue. However, when your app is at scale (millions of users on thousands of types of devices) then this process gets a bit more involved. I’ve learned to rely on Crashlytics in helping to determine what issues need to be resolved quickly. In doing so we have developed a set of steps that help us mitigate risk when new issues arise on the MyFitnessPal app.

 

App Scale and Implementing Post Release Risk Mitigation

 

Crashlytics is good for small and large apps but it really starts to shine when it’s run in an app that is at scale (millions of users/installs) because you start seeing issues you’ve never experienced or even thought could occur in your app. You will get reports of crashes in 3rd party frameworks (like ad frameworks, etc.) as well as other libraries along the way.

 

At MyFitnessPal Crashlytics has helped us catch an enormous amount of issues. Because Crashlytics exposed the issues quickly and accurately with a lot of details we have been able to assess the issues sooner and with greater confidence. Using the tool has also cut costs dramatically as well since it is a free product. Our risk analysis process helps us determine if the issue needs to be immediately fixed via hotfix or if the issue is mild enough to wait for the next dot release (a dot release would be moving from 3.0.1 to 3.0.2 or from 3.0 to 3.1 – it varies from company to company).

 

The Dashboard and Risk Review

 

I feel it’s important to see the Crashlytics dashboard for an app that has millions of installs because that level of detail that we have that helps determine our next course of action. The screenshot below is the Crashlytics Dashboard for the MyFitnessPal Android App as of the latter half of May 2014.

Crashlytics dashboard for the MyFitnessPal Android Application

 

 

The dashboard view provides a great number of details as outlined by table below.

 

 

1.

App / Package Name

The application name and package name.

2.

Version Selector

Select a version to inspect or view all versions of your app in aggregate. I have selected version 3.1.1 (4685). This is the  version name (3.1.1) and the version code (4685) that is in your AndroidManifest.xml. The selected version relates to #12 below.

3.

Open / Closed issues

Toggle between open and closed issues or display all.

4.

Crash / Non-Fatals

Toggle between Crashes and Non-Fatal issues.

5.

Date/Time Selector

Select a time or date range for the issues that you want to inspect.

6.

Search

Search for logs, keys, issues, etc.

7.

Issue Total

Total number of  issues that have been created as a result of various crashes and non-fatals for the selected version / total of number of  issues for crashes and non-fatals for the entire application if ‘All’ is selected.

8.

Total Crashes and Total Non-Fatals with User Counts

The total number of non-fatal crashes and the total number of users affected by the non-fatal crashes. Directly beneath this is the total number of  crashes and total number of users affected by the crashes.

9.

Time / Date Range Chart

A visual chart representation of the number of crashes over a given time.

10.

Issue List Count for Severity / Select All

The total number of crashes for the given severity. The severity of the issue is ranked by Crashlytics on a 1-5 scale. In this screen shot you will notice 5/5 bars are blue. This means this issue is a severity level 5 (highest severity). You can also use the checkbox next to the issue count to select all issues in the list and perform mass editing.

11.

Issue

This is the issue line. It shows the issue ID (#26909) as well as other info about the issue. The root source code cause is shown with line number.  Click on this to visit the issue detail page as shown earlier in this article.

12.

Version Number

The version number of the application when the crash occurred. If you have ‘All’ selected in the version selector, you will see various values in this column in the list. Since I have selected ‘3.1.1  (4685)’ in the version selector all of the issues in the list will have the same value here.

13.

Crash Count

Total number of crashes this issue has caused.

14.

Affected Users Count

The total number of users that this issue has affected.

 

Using the data above along with the data in Crashlytics Answers you can gauge your risk quite easily. An additional bonus that you get for free by using Crashlytics is that their severity ranking on Crashlytics is pretty accurate and is a good place to start when assessing risk. I’m not sure of the exact implementation of their severity algorithm but it seems to be a combination of crash occurrence/issue persistence (does it continually keep happening) and breadth of the crash across Android OS and devices combined with affected users.

 

The risk analysis is pretty simple. Once you release a new version of your app. Check the Crashlytics dashboard daily and perform the following review:

 

Look for the highest occurring crash across the breadth of installs across the various OS’s.

 

Example: If a crash is only affecting Droid Razr devices running Android 2.3.9 and our install base says 0.03% of our users use this device and that accounts for .001% of our total users  … well .. its probably not that big of an issue. However, if we see that we have a crash occurring on all Samsung S3 and Samsung S4 devices with Android 4.+ and our install numbers prove that this accounts for 60% of our install and/or user base, then that means we have a higher priority issue that probably needs a hotfix. We’ll need to be ship the hotfix as soon as possible in order to mitigate the risk of loss of existing and new users.

 

Below is how I perform a risk analysis for a crash. Please note, the first time you do this it will take a few extra minutes because you are cross-referencing data, but after you do it a few times the process will become VERY quick and you probably won’t need to reference Crashlytics Answers for the statistics as often. I do recommend that you still review your statistics in Crashlytics Answers every few weeks and at least once a month to make sure your heuristics are kept up to date (not to mention all the other great info in there – which should be a post in itself).

 

Crashlytics Issue Risk Analysis Steps

 

  1. Review the issue list and the following metrics:

    1. Severity (Crashlytics usually nails this pretty well). I always look at the 5/5’s first.

    2. Total number of crashes this issue has caused.

    3. Total number of users affected.

  2. Choose an issue you want to drill down into. Once the issue is opened in the issue details screen (as shown in the sections above) review the following metrics:

    1. Android Operating System Exposure – How many different OS’s are affected?

    2. Android Device Exposure – Percentage of various devices affected?

  3. Now cross reference these metrics with your current Crashlytics Answers statistics to find the most popular Android Devices and Android OS’s for your app. Do not skip this step!This is different for every app and every market!

    1. Record/Remember the Top 80% of Android OS: Usually the first 3-5 are going to represent your 80%

    2. Record/Remember the Top 10 Android Devices – As your app grows in install base (especially when you trend into the millions of installs) you will see that your top devices are usually around 100K installs to 1M+ installs on a particular device. Really pay attention to these devices because you’ll want to be able to quickly identify your top devices that might be affected.

  4. Determine if it’s a hotfix issue (an issue that needs to be fixed right now or can wait for the next release). Please note, each company’s risk tolerance is different than the next. Adjust to your own risk tolerance as you see fit. MyFitnessPal has a different risk tolerance than my news reading app. The numbers below are generalizations.

    1. If the issue is affecting more than 1% of your users, it’s definitely a hotfix issue.

      1. Again, this is highly subjective. If you have 10 users out of 1000 getting some really obscure error that rarely happens then you may want to hold off on fixing it. This is up to you. But at least you now have the data to come to that conclusion.

    2. If the issue is affecting one of your top devicesby more than 10% of the issue device ratio (Issue per device type) it’s probably a candidate for a hotfix release.

  5. If hotfix is necessary, simply update the source and ship an update and start this process again.

 

Caveat: If you feel the issue at hand is something that needs to be fixed immediately (metrics aside) then by all means, fix it. This is only a rough process which I use to help determine if I should fix an issue immediately or later. This is a general guideline I use, feel free to adjust accordingly.

 

 

Crashes at Scale

 

Another thing you’ll notice when your app gets to scale is that you start getting crash reports for your app that happen in parts of the code that you do not own. Examples of this include ad frameworks, open source libraries or commercial third party libs (charting, etc). When you encounter issues like this you have a few options:

 

  • Extend the class that is causing the issue (if possible) and fix the issue.

  • If the code is open source, fork it and fix it, submit a pull request to the open source project and ship the app with your forked code until the fix is in the open source project.

  • Contact the vendor and have them fix it.

 

I’ve used all three of these with mixed success. However, sometimes there is an error you simply cannot fix; for example, a bug in the Android framework (yes this does happen). Your best course of action is to try to catch the error in your source and gracefully handle it as Android OS updates do not happen that often on devices (unless the user is fortunate enough to be running a Nexus device – but even that gets limited and is slow).

 

 

Logging Exceptions with Crashlytics

 

Ok, the reports and data are great, but how do I log these exceptions!?!

 

Crash monitoring in Crashlytics is built in. You simply add it to your entry point of your application (as was done in the installation portion of the app via the plugin) and at that point crash reporting is handled for you. The reports are delivered over SSL so you don’t have to worry about the security of the information transmitted. The source for Crashlytics is quite small (~45kb) and minimally affects the startup time of your application. However, this is not the end of Crashlytics reach. It can do much more.

 

 

Logging Caught Exceptions

When writing an app you sometimes have to wrap your code in a try/catch. Maybe it’s a network failure you’re expecting, maybe it’s a file read/write issue or maybe it’s a null that sometimes happens when the app is in a certain state. These exceptions should not happen, but sometimes they do. You and your team do your best to handle these issues gracefully so that the app doesn’t crash. Unfortunately at the end of the day you don’t really have any idea how many times a particular exception is being caught. Crashlytics allows you to log caught exceptions like this:

 

Crashlytics.logException(e);

 

This will log the exception as a non-fatal exception in Crashlytics. You can review this data as you view a normal crash. All of the same data is displayed. Error line number, stack trace, OS, Device type, etc. This is shown below in a recent screenshot of a cross platform game I helped develop, QONQR.

 

Screenshot of the non-fatal exception details for the QONQR Android app. Here we have a problem with our onPause event inside of our QonqrMap activity in Android. We have since fixed it (as there is no data in the date chart) yet we leave it open for review as we’re making changes still.

 

User Information

At times in the debugging lifecycle you’ll find that particular crashes are only occurring for particular users. These issues can be especially hard to squash. To help track users and crashes Crashlytics allows you to log user information to help you identify a user. This is done with one of the following methods:

 

  • Crashlytics.setUserIdentifier(String identifier);

  • Crashlytics.setUserName(String name);

  • Crashlytics.setUserEmail(String email);

 

You can use the setUserIdentifier method to set a id, number or hashed value that uniquely identifies the user of your app without disclosing or transmitting any of their personal information. You can also use the other methods listed to send up data about the user.

 

Custom Keys

 

On top of user information it is also useful to keep track of context when a crash occurs. Context can help you pinpoint the root cause of an issue fairly quickly. Crashlytics allows you to log contextual data by using custom keys as such:

 

  • Crashlytics.setBool(String key, boolean value);

  • Crashlytics.setDouble(String key, double value);

  • Crashlytics.setFloat(String key, float value);

  • Crashlytics.setInt(String key, int value);

 

A couple example of how you could use this:

 

  • Crashlytics.setInt(“health_points”, 1337);

  • Crashlytics.setString(“last_action”, “logged-food-entry”);

 

This data is sent with the crash to Crashlytics and you can view it in the issue details screen. Please note, Crashlytics limits you to 64 key/values pairs though might allow more if you contact support.

 

Tips and Tricks

Below are a few tips and tricks I usually share with folks when they first start using Crashlytics. I hope they help you out.

 

Gradle Build Variants for Debug and Release Builds

Crashlytics apps are added automatically to the Organization via the package name. You can add some logic around the Crashlytics initialization so that it only runs during release mode. If you don’t do this you’ll run into some false positives in your Crashlytics dashboard. To get around this,  I use Gradle and build variants. Therefore, in debug mode my package name is com.donnfelker.myapp.debug and in release mode it is com.donnfelker.myapp. This helps me keep my development crashes out of my release crashes.

 

You can implement this with a simple build variant in Gradle like with this code (edit/remove the proguard config if you need to):

 

buildTypes {

       debug {

           packageNameSuffix ‘.debug’

       }

       release {

           proguardFile ‘proguard-project.txt’

       }

   }

 

Now when you build ‘.debug’ will be appended to the package name for debug builds. Please note, you will notice I have ProGuardincluded above. Crashlytics plugin will automatically upload the ProGuardmapping to Crashlytics so that your stack traces are not obfuscated! Awesome!

 

Fragment getActivity() is at least 50% of the Errors at First

This is an easy one. Over 50% (I’d go as far to say 80%) of the apps that use Fragments do not check for null when the getActivity() method is called. This results in a ton of NullPointerExceptions being thrown (this causes the app to crash).

 

Your new rule of thumb should be: getActivity() will ALWAYS be null. If you think that way, you will change the way you code when using getActivity() and in doing so you will always be checking for null. Doing that will save you a ton of crash reports.

 

NullPointerException is your Best Friend

Speaking of null pointer exceptions … As I’ve said in many of my presentations – expect everything to be be null especially getActivity() in a Fragment. The NullPointerException is one of the easiest exceptions to fix (when it’s in your code). These ones are quick hits – simply fix it, test it and ship it. These are real easy ones to do. But please note, at scale you will see more NullPointerExceptions than you ever thought you would, and a lot of them will be in places you least expected them to happen. Happy hunting. :)

 

Wrap Up

Since Android was introduced to the public in 2008 I’ve been developing apps for the Android platform. Many of my original apps were in the first 1000 published to the Android Market (now known as Google Play) and even during those times my major concern was around crash reporting. I’ve used a slew of tools over the years and while some have come close to the usability, cost, and feature set of Crashlytics none has yet to surpass it. Crashlytics is the first library I install on any app that is going to be released on Google Play or the Amazon App Store. It probably should be yours too.




Made possible by … 

A huge thank you goes out to Hemal from the Crashlytics team for all the help with the Crashlytics products, I couldn’t have done it without you. Thanks again!

 

FYI – Crashlytics also offers beta distribution through Beta by Crashlytics (kind of like Testflight, but its by Crashlytics) and mobile analytics with Answers by Crashlytics (which we briefly touched on in this article). Similar to the experience they deliver with crash reporting, these new services were a great tool to have in my toolbelt. If you use beta distribution or are looking for a strong mobile app analytics tool, you should definitely check them out.

 

Learn more about Crashlytics for Android.


This article was also posted in the Product Showcase section for sponsors at CodeProject. This review is intended to provide you with information that is considered useful and of value to developers.