I ran into an interesting bug this week while doing some Titanium development. I’m working on a dual-platform mobile app solution for a client, and the last couple of Android test builds were absolutely riddled with
OutOfMemoryError exceptions. They popped up in almost all screens with no rhyme or reason. This made any steps to reproduce quite worthless.
Here’s a sample of the Android OutOfMemoryError in Titanium I was repeatedly seeing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
OutOfMemoryError; Titanium 3.0.0,2013/10/31 18:49,a5894b3 java.lang.OutOfMemoryError at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:502) at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:355) at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:785) at android.content.res.Resources.loadDrawable(Resources.java:1965) at android.content.res.Resources.getDrawable(Resources.java:660) at org.appcelerator.titanium.util.TiUIHelper.getResourceDrawable(TiUIHelper.java:833) at org.appcelerator.titanium.util.TiUIHelper.getResourceDrawable(TiUIHelper.java:828) at org.appcelerator.titanium.util.TiFileHelper.loadDrawable(TiFileHelper.java:279) at org.appcelerator.titanium.util.TiUIHelper.buildBackgroundDrawable(TiUIHelper.java:501) at org.appcelerator.titanium.util.TiUIHelper.buildBackgroundDrawable(TiUIHelper.java:547) at org.appcelerator.titanium.view.TiUIView.handleBackgroundImage(TiUIView.java:920) at org.appcelerator.titanium.view.TiUIView.processProperties(TiUIView.java:671)
Unfortunately, this error log is not very helpful as the error is coming from the Titanium SDK and not from any specific line of code I had written.
This error initially showed up in one spot, where I was attempting to download and save an image from a remote URL. Unfortunately, I made the mistake of focusing my debugging efforts on that particular area. Eventually, when I saw the same errors on various device models, I stepped back.
I had already done some optimization of image assets, but given the nature of the error (coming from
BitmapFactory) I had a feeling the culprit was the graphic assets.
Android graphic resources are organized (at least partly) by screen density. So I took a leap and renamed the directory housing my high-density assets. This meant the app would use the normal density graphics, as no high density graphics would be available. I expected the app, if it worked, to look pixellated.
The app worked. And I was wrong.
Being the kind of person I am, having a working solution wasn’t good enough. I needed to know why it worked. So I went back and studied my assets off. What I had done was generated extra-high density graphics into the high density folder. So the devices we were testing on were using graphics that were outside their capability to display.
This turned out to be an easy fix; it was just a frustrating couple of days. And it served as a harsh reminder that debugging isn’t always about the code you’ve written.