Sample app taking pictures with camera and adding them in a ScrollView crashes on iPhone 4 after 7-8 images are added. The log shows a "Memory warning" message. No issues found with iPhone 5.
var damageImages = [];
var win = Ti.UI.createWindow({
backgroundColor : '#fff'
});
var imageView = Ti.UI.createView({
layout : 'horizontal',
width : Ti.UI.FILL,
height : Ti.UI.SIZE
});
var successCallBack = function(e) {
if (e.mediaType != Ti.Media.MEDIA_TYPE_PHOTO) {
takePhotoBtn.enabled = true;
pickPhotoBtn.enabled = true;
return false;
}
var filename = (new Date().getTime()) + ".jpg";
var newImageWrapperView = Ti.UI.createView({
backgroundColor : '#000',
left : '8dp',
top : '10dp',
height : '96dp',
width : '96dp',
isImage : true
});
newImageWrapperView.id = filename;
var newImageView = Ti.UI.createImageView({
isImage : true,
zIndex : 10
});
newImageView.opacity = 0.5;
newImageWrapperView.add(newImageView);
var bgImage = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, filename);
newImageView.image = bgImage.getNativePath();
//I need this for let use..
damageImages.push({
"id" : bgImage.getNativePath(),
"name" : filename,
"description" : ""
});
//resizing code also removed
/*
var imageModify = Ti.UI.createImageView({
image : e.media
});
var width = imageModify.toImage().width
var height = imageModify.toImage().height
imageModify = null;
var scaledImage = require('lib/utils').resizeKeepAspectRatioNewWidth(e.media, width, height, Config.imageMaxWidth);
*/
bgImage.write(e.media);
//scaledImage = null;
bgImage = null;
imageView.add(newImageWrapperView);
takePhotoBtn.enabled = true;
pickPhotoBtn.enabled = true;
};
var errorCallBack = function(e) {
takePhotoBtn.enabled = true;
pickPhotoBtn.enabled = true;
alert(L('erroronselectimage', 'Error while selecting image'));
};
var cancelCallBack = function(e) {
takePhotoBtn.enabled = true;
pickPhotoBtn.enabled = true;
};
var takePhotoBtn = Titanium.UI.createButton({
style : Titanium.UI.iPhone.SystemButtonStyle.BORDERED,
title : 'Take Photo'
});
takePhotoBtn.addEventListener('click', function(e) {
Ti.Media.showCamera({
success : successCallBack,
error : errorCallBack,
cancel : cancelCallBack,
allowEditing : false,
saveToPhotoGallery : true,
mediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO]
});
takePhotoBtn.enabled = false;
pickPhotoBtn.enabled = false;
});
var pickPhotoBtn = Titanium.UI.createButton({
style : Titanium.UI.iPhone.SystemButtonStyle.BORDERED,
title : 'Pick Photo'
});
pickPhotoBtn.addEventListener('click', function(e) {
Ti.Media.openPhotoGallery({
success : successCallBack,
error : errorCallBack,
cancel : cancelCallBack,
allowEditing : false,
mediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO]
});
takePhotoBtn.enabled = false;
pickPhotoBtn.enabled = false;
});
var flexSpace = Titanium.UI.createButton({systemButton : Titanium.UI.iPhone.SystemButton.FLEXIBLE_SPACE});
var toolbar = Ti.UI.iOS.createToolbar({
borderTop : true,
borderBottom : false,
height : 45,
zIndex : '100',
bottom : '0dp'
});
toolbar.items = [flexSpace, takePhotoBtn, pickPhotoBtn, flexSpace];
var scrollView = Ti.UI.createScrollView({
layout : 'vertical',
top : 0,
bottom : 45
});
scrollView.add(imageView);
win.add(scrollView);
win.add(toolbar);
win.open();
During tests, devices even crashed entirely (e.g. reboot).
Hi, I tested with iPhone 4s and app is crashing most of the cases after taking 6-8 images using camera. I don't think this is problem with adding to Scrollview. Because app is crashing when we open the camera using
showCameraonly. Can you please make this high Priority. Thank you.HI, Verified The issue with iPhone 5 also and Crashes on that also but number of images taken are quite high approx 30 to 35. **Device Crash Log**
Incident Identifier: DD9157D8-314E-4EA2-825A-957D681B5A2D CrashReporter Key: bd158f36569796279d86b0f6c5ca6b83e9c330f3 Hardware Model: iPhone5,1 OS Version: iPhone OS 6.0 (10A405) Kernel Version: Darwin Kernel Version 13.0.0: Sun Aug 19 00:31:06 PDT 2012; root:xnu-2107.2.33~4/RELEASE_ARM_S5L8950X Date: 2013-04-10 14:55:31 +0530 Time since snapshot: 1306 ms Free pages: 2738 Active pages: 1306 Inactive pages: 19709 Throttled pages: 84705 Purgeable pages: 251 Wired pages: 149309 Largest process: conceptTest Processes Name <UUID> rpages recent_max [reason] (state) assetsd <53881b88f0bf3948871456faf8fe5587> 1522 1522 [vm] (daemon) (idle) MobileMail <7ddddc607bec3f1f9ac5212a22279714> 1355 1355 (resume) (continuous) MobilePhone <3fefa53221ce3ccc867ade7d0f2b743a> 1300 1300 (resume) (continuous) kbd <98304e71b044348cbbc1fd3a7f0cda5a> 591 591 (daemon) tccd <96c9594f71b53a7fb5db7bd63ca52c90> 285 285 (daemon) conceptTest <33514e224eeb36d182595067e925de72> 159731 160082 [per-process-limit] (frontmost) (resume) ptpd <c03db1af00a7381ab52c2e01ec25e21c> 1094 1094 (daemon) dataaccessd <0db5b1392b6c391496eaa9eff8122088> 1089 1089 (daemon) syslogd <76c7ece27e1930ccba213a9ed4d6ead0> 187 187 (daemon) wifid <3c1b8ae2bd1f3453b8a34769c57a800a> 636 636 (daemon) iaptransportd <589c47b3c06c3c8bb33b4044c6a94321> 355 355 (daemon) locationd <5cca2615d1c23508808fd442ccf28470> 1263 1263 (daemon) mediaserverd <80947eda91eb396d841f65d9deac2d76> 28835 28835 (daemon) timed <8984d2e17535329cbfd4baf3a9b8f963> 410 410 (daemon) lsd <e83b45e404e63cd785bf3e4a1780015f> 356 356 (daemon) SpringBoard <b9e4c47e6285309aa0971087f76cb64c> 5622 5622 backboardd <29faa2a7d1f1304c87418beb50a7e458> 5607 5607 (daemon) fairplayd.N41 <185d84e38a5230ffaaa6b21cdcbb4754> 326 326 (daemon) fseventsd <df4490b9277930f0b063da0f820fea5b> 351 351 (daemon) imagent <b8a6dcb0b80d366bb8396f0eb131bacb> 436 436 (daemon) mDNSResponder <8a128a0397f93f6f8ede1df8f60759a5> 354 354 (daemon) lockdownd <66d819d22a643069b42aa2dbd7229db2> 396 396 (daemon) powerd <f60cc21c1b513b888db7563a2ad586ee> 240 240 (daemon) UserEventAgent <4df6d63523a138f19d67bd59137827e1> 744 744 (daemon) softwareupdated <ce42d24d6b2e3913914f06d5c2f5412d> 292 292 (daemon) mobileassetd <f53eac44f107369ebf0ce64e9f051a44> 427 427 (daemon) softwareupdatese <fcffee02207139fa875e7c52cb2032b0> 630 630 (daemon) springboardservi <d5de7adf79053b1bb5850daf7abf2a53> 0 0 (daemon) DTMobileIS <9d4add29c730382583f03d7a8df474cc> 0 0 (daemon) absinthed.N41 <7d9923eda625387ba90685167a49c661> 139 139 (daemon) mediaremoted <4f79c3873e8b35a3ab9c14b88131fc15> 398 398 (daemon) filecoordination <5ca98b31b5d93b26a26c5011bc724908> 225 225 (daemon) notification_pro <2dca4ba7b48c36e1a80c191034c70f70> 225 225 (daemon) afcd <58855a00a1dc3c99be7453efe0b5dfc7> 191 191 (daemon) distnoted <79d66cd42c243074afe7bab01d31f354> 213 213 (daemon) apsd <6f919f4ed7a3353b89304db1493a6ffd> 449 449 (daemon) networkd <305a7d187fce35d0bc48d0fbed74813e> 298 298 (daemon) aggregated <756a686c7ee2314e8891549847e28db8> 132 132 (daemon) BTServer <ab97543dbbb13651b170bb7a2d35ea3e> 419 419 (daemon) configd <fb01e670ce773187a08ae6af05e81f19> 532 532 (daemon) CommCenter <e4553263effe374e8480d4057c291b77> 795 795 (daemon) notifyd <81c20c784ece3554a7a4bf7944a450ff> 230 230 (daemon) ReportCrash <41677a971e73356db9dd24f1a6814432> 380 380 (daemon) **End**Hi, This particular line is interesting here, in the above device log. **conceptTest <33514e224eeb36d182595067e925de72> 159731 160082 [per-process-limit] (frontmost) (resume)**
The way the code is written the imageView loads the entire image into memory. The RGB data of the image occupies about 30 MB in VM (Use VM tracker on Instruments) So once you have taken about 8 photographs the app gets killed due to lack of memory. Given that the imageView is going to be at most 96x96 in size, it would be better to resize the image (keeping aspect ratio intact) and then use the resized image in the thumbnail view. The original image can be loaded later when needed. Code is attached below to show loading of scaled images. App no longer crashes. Scaling Logic
Full Codevar imgWid = e.media.width; var imgHt = e.media.height; var scaleW; var scaleH; if (imgWid > imgHt) { scaleW = 96; scaleH = Math.floor((imgHt * 96)/imgWid); } else { scaleH = 96; scaleW = Math.floor( (imgWid*96) /imgHt); } Ti.API.info(imgWid+' '+imgHt+' '+scaleW+' '+scaleH); newImageView.image = e.media.imageAsResized(scaleW, scaleH);var damageImages = []; var win = Ti.UI.createWindow({ backgroundColor : '#fff' }); var imageView = Ti.UI.createView({ layout : 'horizontal', width : Ti.UI.FILL, height : Ti.UI.SIZE }); var successCallBack = function(e) { if (e.mediaType != Ti.Media.MEDIA_TYPE_PHOTO) { takePhotoBtn.enabled = true; pickPhotoBtn.enabled = true; return false; } var filename = (new Date().getTime()) + ".jpg"; var newImageWrapperView = Ti.UI.createView({ backgroundColor : '#000', left : '8dp', top : '10dp', height : '96dp', width : '96dp', isImage : true }); newImageWrapperView.id = filename; var newImageView = Ti.UI.createImageView({ isImage : true, zIndex : 10 }); newImageView.opacity = 0.5; newImageWrapperView.add(newImageView); var bgImage = Titanium.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, filename); //newImageView.image = bgImage.getNativePath(); //I need this for let use.. damageImages.push({ "id" : bgImage.getNativePath(), "name" : filename, "description" : "" }); var imgWid = e.media.width; var imgHt = e.media.height; var scaleW; var scaleH; if (imgWid > imgHt) { scaleW = 96; scaleH = Math.floor((imgHt * 96)/imgWid); } else { scaleH = 96; scaleW = Math.floor( (imgWid*96) /imgHt); } Ti.API.info(imgWid+' '+imgHt+' '+scaleW+' '+scaleH); newImageView.image = e.media.imageAsResized(scaleW, scaleH); //resizing code also removed /* var imageModify = Ti.UI.createImageView({ image : e.media }); var width = imageModify.toImage().width var height = imageModify.toImage().height imageModify = null; var scaledImage = require('lib/utils').resizeKeepAspectRatioNewWidth(e.media, width, height, Config.imageMaxWidth); */ bgImage.write(e.media); //scaledImage = null; bgImage = null; imageView.add(newImageWrapperView); takePhotoBtn.enabled = true; pickPhotoBtn.enabled = true; }; var errorCallBack = function(e) { takePhotoBtn.enabled = true; pickPhotoBtn.enabled = true; alert(L('erroronselectimage', 'Error while selecting image')); }; var cancelCallBack = function(e) { takePhotoBtn.enabled = true; pickPhotoBtn.enabled = true; }; var takePhotoBtn = Titanium.UI.createButton({ style : Titanium.UI.iPhone.SystemButtonStyle.BORDERED, title : 'Take Photo' }); takePhotoBtn.addEventListener('click', function(e) { Ti.Media.showCamera({ success : successCallBack, error : errorCallBack, cancel : cancelCallBack, allowEditing : false, saveToPhotoGallery : false, mediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO] }); takePhotoBtn.enabled = false; pickPhotoBtn.enabled = false; }); var pickPhotoBtn = Titanium.UI.createButton({ style : Titanium.UI.iPhone.SystemButtonStyle.BORDERED, title : 'Pick Photo' }); pickPhotoBtn.addEventListener('click', function(e) { Ti.Media.openPhotoGallery({ success : successCallBack, error : errorCallBack, cancel : cancelCallBack, allowEditing : false, mediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO] }); takePhotoBtn.enabled = false; pickPhotoBtn.enabled = false; }); var flexSpace = Titanium.UI.createButton({systemButton : Titanium.UI.iPhone.SystemButton.FLEXIBLE_SPACE}); var toolbar = Ti.UI.iOS.createToolbar({ borderTop : true, borderBottom : false, height : 45, zIndex : '100', bottom : '0dp' }); toolbar.items = [flexSpace, takePhotoBtn, pickPhotoBtn, flexSpace]; var scrollView = Ti.UI.createScrollView({ layout : 'vertical', top : 0, bottom : 45 }); scrollView.add(imageView); win.add(scrollView); win.add(toolbar); win.open();Closing ticket as "Won't Fix".