-
Notifications
You must be signed in to change notification settings - Fork 916
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Urgent: map stop working with many remote markers #337
Comments
I think there is a dead link (404 image). |
You could maybe try this: map.addMarker({ |
Hi there, I have a app that load up to 900 Markers with different images and it works. Do you resize the marker images? |
Yes, I do resize them. Actually there could not be any 404. The images are there - all of them. But even when it should be a 404, the plugin should handle this correctly. I really do not have any idea, how to solve this. I will provide you guys my "fake" JSON file later, maybe you could debug better with this. |
Try do set the markers without resizing. I believe that is the problem.
|
Resizing the icon makes a new image data internally that domains some For example, loading 90 icon images with resizing means your app makes So if you use bunch of different images for icon, that should be resized in On Sat, Dec 20, 2014, 6:08 AM TheMassassian [email protected]
|
I'm afraid to tell you, but even when I do not resize, it will crash. I just simulated more markers on my server (currently there are just 6 markers, I do some tricks with php)
Do I have any glitches in my code? Something that causes a memory leak? // markers
var markers = $scope.getMarkers();
// define array
var points = [];
for(var i=0;i<markers.length;i++)
{
var obj = markers[i];
// grab the first marker for circle drawing
if(i == 0) {
var pos = new plugin.google.maps.LatLng(obj["lat"], obj["lng"]);
$rootScope.map.addCircle({
'center': pos,
'radius': 2500,
'strokeColor' : '#FFFFFF',
'strokeWidth': 3,
'fillColor' : 'rgba(255,145,1,0.3)'
});
}
console.log(obj['uid']);
//return false;
//var attrName = key;
//var attrValue = obj[key];
var latLng = new plugin.google.maps.LatLng(obj["lat"], obj["lng"]);
points.push(latLng);
$rootScope.map.addMarker({
'position': latLng,
'uid': obj["uid"],
'firstname': obj["firstname"],
'picture': obj["picture"],
'isFavorite': obj["isFavorite"],
'isMe': obj["isMe"],
'picture_profile': obj["picture_profile"],
'icon': {
'url': obj["icon"],
'size': {
'width': 40,
'height': 50
}
},
'markerClick': function(marker) {
$scope.showUserOverlay(marker);
}
});
}
//console.log(points);
$scope.latLngBounds = new plugin.google.maps.LatLngBounds(points);
$rootScope.map.moveCamera({
'target' : $scope.latLngBounds
}); |
Just made some debugs:
As soon as I remove the "icon" url -> it works perfectly. This has nothing to do with the size of the icon. There must be a problem accessing so many remote markers... |
I see. Could you tell me the all icon urls? |
If you don't want to share the URL publicly, send me an e-mail please. |
Just sent you an email. Thanks! |
Happy new year to all of you guys. Sorry when I jumped on this so quickly but any news on this bug? |
@hirbod In your code, at least, you need to improve your code. For example: map.addMarker({
"position": new plugin.google.maps.LatLng(...),
"icon": ...,
"uid": data.uid,
"markerClick": function(marker) {
var uid = marker.get("uid");
// ie. jQuery
$.getJSON("http://yourserver/getDetail/" + uid, function(response) {
alert(response);
});
} Further more, using one function for the same process is better memory performance in Javascript. Better code: map.addMarker({
...
"markerClick": onMarkerClick
});
function onMarkerClick(marker) {
....
} Bad code: map.addMarker({
...
"markerClick": function() {....}
}) |
Hi Masashi, thanks for the tips. I know, there is some potential to optimize, and I will incorporate your suggestions, but still, it crashes only when I use the external images. If I leave them to the defaults, the map will load, no matter how many markers I've used... |
Got the fix for this problem. It's not caused trough this plugin directly. Seems like this is the problem: actually cordova has a bug which creates a new iframe every .exec() call is fired from bridge. As soon as 999+ iframes are reached, maps plugin crash. When I fire $('iframe').remove(), it works. I'm sure that this is my problem. This bug seems only to happen on 3.7.0+ and is fixed in 3.8.0.dev For now (till 3.8.0) is out, $('iframe').not(':last').remove(); fix most of my issues. |
Wow! I know Cordova creates iframe internally, but I didn't reach the idea of this. |
💯 |
I'm so sad.... but this fixes at least some other problems, but not this one. It still crash when I have to many remote markers... DAMN! |
SendDelegateMessage(NSInvocation *): delegate (webView:decidePolicyForNavigationAction:request:frame:decisionListener:) failed to return after waiting 10 seconds. main run loop mode: kCFRunLoopDefaultMode event tried to add the remove stuff inside the addMarkers function.. im going crazy... |
I got some new / better logs.
This seems to be something interessting: Could this help you to improve your code? |
When I have more then 60 markers with remote image... MAPS CRASH. My contractee is going to kill me when this app dies with 60 markers.. and I'm getting really nervous right now. |
Marker.m file: changed dispatch_queue_t gueue = dispatch_queue_create("GoogleMap_addMarker", NULL);
dispatch_sync(gueue, ^{ to //dispatch_queue_t gueue = dispatch_queue_create("GoogleMap_addMarker", NULL);
dispatch_async(dispatch_get_main_queue(), ^{ AND DAMN YEAH. IT WORKS! Just need to download async, not sync. As Google SDK requeires all calls in the main thread, I've just called dispatch_get_main_queue() instead of 600 Remote markers work, then:
Any feedback on this, Masashi? |
I'm in outside right now. My car gets an engine trouble (over heat). On Sat, Jan 24, 2015, 4:40 PM Hirbod [email protected] wrote:
|
https://code.google.com/p/gmaps-api-issues/issues/detail?id=5756 So after 4 months of work... this plugin (or Google Maps SDK) is useless for me without Cluster... cause it can't display more then 500-600 (after my fix) markers.. (in a small radius of 2,5 miles) |
I still see some other bugs in Markers. Breakpoint exception.
throwing: 'NSInvalidArgumentException', reason: '*** setObjectForKey: object cannot be nil |
FINALLY I GOT IT. Ok... there were a lot of logical bugs and many cases were data could not be set.
Things I did:
-dataWithContentsOfURL:doesn’t return until the URL connection is over, which can take up to 2 minutes in the worst case (when the host isn’t available and the connection times out). Until that method returns, the UI is completely blocked. The user can’t do anything, the app won’t respond to any touches, including any for scrolling your tableview. Unacceptable.
- (void)downloadImageWithURL:(NSURL *)url completionBlock:(void (^)(BOOL succeeded, UIImage *image))completionBlock
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if ( !error )
{
UIImage *image = [[UIImage alloc] initWithData:data];
completionBlock(YES,image);
} else{
completionBlock(NO,nil);
}
}];
} which will do a Async request to download the markers. Last but not least: /***
* Load the icon from over the internet
*/
NSData *imgData = [self.iconCache objectForKey:iconPath];
if (imgData != nil) {
UIImage* image = [UIImage imageWithData:imgData];
if (width && height) {
image = [image resize:width height:height];
}
marker.icon = image;
[self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId];
} else {
//dispatch_queue_t gueue = dispatch_queue_create("GoogleMap_addMarker", NULL);
dispatch_async(dispatch_get_main_queue(), ^{
NSURL *url = [NSURL URLWithString:iconPath];
//NSData *data = [NSData dataWithContentsOfURL:url options:NSDataReadingMapped error:nil];
// download the image asynchronously
[self downloadImageWithURL:url completionBlock:^(BOOL succeeded, UIImage *image) {
if (succeeded) {
[self.iconCache setObject:image forKey:iconPath];
if (width && height) {
image = [image resize:width height:height];
}
marker.icon = image;
// The `anchor` property for the icon
if ([iconProperty valueForKey:@"anchor"]) {
NSArray *points = [iconProperty valueForKey:@"anchor"];
CGFloat anchorX = [[points objectAtIndex:0] floatValue] / image.size.width;
CGFloat anchorY = [[points objectAtIndex:1] floatValue] / image.size.height;
marker.groundAnchor = CGPointMake(anchorX, anchorY);
}
// The `infoWindowAnchor` property
if ([iconProperty valueForKey:@"infoWindowAnchor"]) {
NSArray *points = [iconProperty valueForKey:@"infoWindowAnchor"];
CGFloat anchorX = [[points objectAtIndex:0] floatValue] / image.size.width;
CGFloat anchorY = [[points objectAtIndex:1] floatValue] / image.size.height;
marker.infoWindowAnchor = CGPointMake(anchorX, anchorY);
}
}
}];
[self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId];
}); I wrap inside a async dispatch and call the download sync. This let the map load much faster and download much faster then ever. Of course, if you have too many markers, you will first see the default marker icon which gets replaced trough the downloaded marker - but this behaviour is better I guess. Maybe you now (I'm really not an experienced Obj-C developer) how to improve this. Next thing is to support markers from file:/// path, then we could download markers outside of the Maps Plugin and pass the internal file:/// documents AND tmp path. I know this should be possible to implement. Hope you can help after your car works fine again. But the most important thing is the long awaited clusterer. |
And I think there is still more potential optimizing this: But for now, my patch will fix the crashed caused trough your plugin, but will not fix the crashes caused trough Google Maps SDK. But the caching method should be improved also. Use https://github.com/FTW/FTWCache This article explains good.. |
Changed the code a little bit: } else {
/***
* Load the icon from over the internet
*/
NSData *imgData = [self.iconCache objectForKey:iconPath];
if (imgData != nil) {
UIImage* image = [UIImage imageWithData:imgData];
if (width && height) {
image = [image resize:width height:height];
}
marker.icon = image;
[self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId];
} else {
//dispatch_queue_t gueue = dispatch_queue_create("GoogleMap_addMarker", NULL);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSURL *url = [NSURL URLWithString:iconPath];
//NSData *data = [NSData dataWithContentsOfURL:url options:NSDataReadingMapped error:nil];
// download the image asynchronously
[self downloadImageWithURL:url completionBlock:^(BOOL succeeded, UIImage *image) {
if (succeeded) {
if (width && height) {
image = [image resize:width height:height];
}
dispatch_async(dispatch_get_main_queue(), ^{
marker.icon = image;
// The `anchor` property for the icon
if ([iconProperty valueForKey:@"anchor"]) {
NSArray *points = [iconProperty valueForKey:@"anchor"];
CGFloat anchorX = [[points objectAtIndex:0] floatValue] / image.size.width;
CGFloat anchorY = [[points objectAtIndex:1] floatValue] / image.size.height;
marker.groundAnchor = CGPointMake(anchorX, anchorY);
}
// The `infoWindowAnchor` property
if ([iconProperty valueForKey:@"infoWindowAnchor"]) {
NSArray *points = [iconProperty valueForKey:@"infoWindowAnchor"];
CGFloat anchorX = [[points objectAtIndex:0] floatValue] / image.size.width;
CGFloat anchorY = [[points objectAtIndex:1] floatValue] / image.size.height;
marker.infoWindowAnchor = CGPointMake(anchorX, anchorY);
}
NSData *imgData = UIImagePNGRepresentation(image);
[self.iconCache setObject:imgData forKey:iconPath];
[self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId];
});
}
}];
});
}
} I think it is a bit more performant now (High priority) but the iconCache seems not to work... |
It's midnight, and I finally got my private time. I'm reading your posts now. |
@hirbod One point, the reason of For the reason, I will modify a little your code. Just a moment. |
@hirbod |
Hi Masashi, Now just incoporate the watchdog and then please, release 1.2.5. Next step: better memory handling and optimization for image resizing. There are still better ways of doing (also keep aspect ratio, set better interpolarity Quality etc.) I will do this next week for you and send you a PR, but this was - for now, the most important bug that has got fixed |
Hi Masashi,
if I try to load more then 100 remote marker images, the map just stops working. From 50-80 it is ok and still fast, then suddently, it stops doing anything. If I set 6000 markers without image, everything works.
Just tested on iOS, I don't know how it would be on android. Please, could you have a look? I know, this problem will for sure be solved with marker cluster, but actually, it is a serious bug. I'm not sure what happen with locale marker images, but at least remote will die.. :(
The text was updated successfully, but these errors were encountered: