I’m experiencing an intermittent crash in my Android application running on a Droid X 2.3.4, using Cordova 1.6.1. I’ve created a sample project (http://bit.ly/IWxTv7) that clearly demonstrates the error on the device, but only intermittently. It’s happening frequently enough that if you run the sample and repeat picking a photo, after about 6 attempts you should see the crash. Also note that this functions correctly on iOS and other Android devices, so the fact that it’s intermittent and device/OS specific has me puzzled.
Description of expected functionality:
The sample allows the user to pick a photo from the library or camera and shows it in an image element on the page. The real application works differently, but this isolates the problem.
What the code is doing:
A click handler on a button is calling the navigator.camera.getPicture method with a FILE_URI destination type. After a photo is picked, the system uses the resulting temporary URI to read the image data and copy it to a persistent location. This uses the readAsDataURL method on the FileReader object. When it works, it takes the result and saves it to a persistent location using the write method on the FileWriter object. When that completes, it returns the URI for the persistent location to the button click event handler, which sets the src attribute of an image element to the persistent URI. (That part doesn’t work, probably because I’m not using it correctly, but it’s not relevant to the real app, so I didn’t bother troubleshooting and don’t need an answer to why that doesn’t work.)
The crash:
Run the app, tap the “Photo” button in the footer. When the photo page loads, tap the “Get from camera” or “Get from library” button. Pick a photo and return to the app. If the process completes successfully, the image element will display a broken image icon. If the process didn’t complete successfully, the UI will remain as is, or the application will crash.
My analysis:
The application crashes intermittently when attempting to execute FileReader.readAsDataURL. I’ve come to this conclusion because it’s always the last log entry I see before it crashes. However, in the past I’ve seen log entries from stuff that’s executed successfully not show up in the console because of an error downstream, so I’m not 100% sure that’s the cause, just a hypothesis. The crash is intermittent, but I was able to reproduce pretty quickly, within 6 attempts. Sometimes it succeeds, but when it fails it appears to always do so when trying to execute readAsDataURL.
Has anyone else encountered errors or crashes attempting to read a local file this way? What is up and how do I fix this? Alternate solutions or workarounds must give me access to the base 64 encoded image data.
If you had the output of “adb logcat” I could probably pinpoint this issue for you but for now I will have to tell you what I suspect. The camera on a Droid X is 8 MP which means it takes a picture of pretty high quality and the file size can be quite large. Now when you attempt to read the file as Base64 encoded data the size of the data gets even larger as base64 imposes a 33% overhead.
So what I suspect is happening is that your application is throwing an OutOfMemoryException and crashing. Sadly you cannot catch and OOM exception so there is nothing to be done except re-work the app to use less memory.
You may want to look at reducing the width/height or quality of the picture to reduce the overall file size. Alternatively, just set your image tag to the FILE_URI you get rather than doing any base64 encoding.