So I have an app which preloads graphics from an API.
I firstly grab all of the data I need from my onboard DB, loop through it and send the user off to a function to download the image, resize it etc.
on iOS this seems to work great, however on Android it keeps falling over.
I'm looking for a more elegant way of doing this, that won't crash the app.
Is there a way I can wait for the getMarker()
function to complete before my loop (from the getMapMarkers()
function) fires another request to it?
Here is my code snippet for that part of my app. The function getMarker()
does the processing of the image and resizing.
function getMarker(url, filename) {
var mapMarker = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, 'map_marker_icons', filename);
// now we need to download the map marker and save it into our device
var getMarker = Titanium.Network.createHTTPClient({
timeout: 30000
});
getMarker.onload = function() {
// if the file loads, then write to the filesystem
if (getMarker.status == 200) {
var image = this.responseData;
// resize to 75 pixel marker
var resizedImage = image.imageAsResized(75, 75);
mapMarker.write(resizedImage);
//I ALWAYS NULL ANY PROXIES CREATED SO THAT IT CAN BE RELEASED
image = null;
resizedImage = null;
mapMarker = null;
} else {
Ti.API.info("Image not loaded");
}
//getMarker = null;
};
getMarker.onerror = function(e) {
Ti.API.info('XHR Error ' + e.error);
//alert('markers data error');
};
getMarker.ondatastream = function(e) {
if (e.progress == 1) {
Ti.API.info(filename + ' Download Complete');
}
};
// open the client
getMarker.open('GET', url);
// send the data
getMarker.send();
}
function getMapMarkers() {
// get the species list back
var db = Ti.Database.open('myDB');
var getSpeciesImages = db.execute('SELECT speciesiconfilename, speciesmapiconurl FROM species where speciesiconfilename <> ""');
// YOU ONLY NEED TO DO THIS ONCE SO DO IT OUTSIDE THE LOOP
var imgDir = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, 'map_marker_icons');
// if the directory doesn't exist, then we need to create it
if (!imgDir.exists()) {
// If the directory doesn't exist, make it
imgDir.createDirectory();
};
// start the loop
while (getSpeciesImages.isValidRow()) {
var filename = getSpeciesImages.fieldByName('speciesiconfilename');
var url = getSpeciesImages.fieldByName('speciesmapiconurl');
getMarker(url, filename);
getSpeciesImages.next();
} // end the loop
getSpeciesImages.close();
// close the database
db.close();
// get the exhibit markers next
getExhibitMapMarkers();
};
Anyone able to help? It's driving me crazy!
Simon
It's more js question than titanium. I prefer to use Q library (https://github.com/kriskowal/q) for such things.
function getMarker(url, filename) {
return function() {
var defered = Q.defer();
...
var xhr = Titanium.Network.createHTTPClient({
timeout: 30000
});
xhr.onload = function() {
...
defered.resolve();
};
xhr.onerror = function(e) {
...
defered.resolve(); // or defered.reject() if you want stop after first error
}
...
xhr.open('GET', url);
xhr.send();
return defered.promise;
};
}
function getMapMarkers() {
...
var imageRequests = [];
while(getSpeciesImages.isValidRow()) {
...
imageRequests.push(getMarker(url, filename));
getSpeciesImages.next();
}
imageRequests.reduce(Q.when, Q(true))
.then(function() {
Ti.API.info('all loaded');
});
...
};
And don't name http client variable same as getMarker() function!