android-maps-utils
android-maps-utils copied to clipboard
App freezes when loading KML layer
I am trying to add KML layer on to the maps. It was working okay with just a ms of freeze when i try to load the small size KML file. But some files are large with size more than 1Mb - 10Mb.. in these all cases app is getting frozen for some time while the layer is adding to the map.
Below is the Asynctask class i am using to read the kml file from local storage path and adding it to maps.
I tried this in many ways using handlers, threads, asynctasks... as i cannot update the UI in background thread... this is causing my app to freeze for some time.
Eventhough it freezes I wouldn't mind but in some device while the app is frozen if the user interacts with the app then app is getting crashed. In some devices it is displaying "wait" dialog.
Please help me out.
` private static class AddKMLLayerToMaps extends AsyncTask<String, String, KmlLayer> {
//added weakreference to avoid memory leaks
private WeakReference<CoverageFragment> weakReferencedFragment;
AddKMLLayerToMaps(CoverageFragment reference) {
this.weakReferencedFragment = new WeakReference<>(reference);
weakReferencedFragment.get().showLoading();
}
@Override
protected KmlLayer doInBackground(String... strings) {
try {
TraceUtils.logE("Coverage kml Path", strings[0]);
FileInputStream fileInputStream = new FileInputStream(strings[0]);
CoverageFragment fragment = weakReferencedFragment.get();
if (fragment == null || fragment.getActivity() == null || fragment.getActivity().isFinishing()) {
return null;
}
KmlLayer kmlLayer = new KmlLayer(fragment.mMap, fileInputStream, getApplicationContext());
fileInputStream.close();
File file = new File(strings[0]);
if (file.exists()) file.delete();
return kmlLayer;
} catch (Exception e) {
weakReferencedFragment.get().hideLoading();
TraceUtils.logException(e);
}
return null;
}
@Override
protected void onPostExecute(KmlLayer kmlLayer) {
super.onPostExecute(kmlLayer);
if (kmlLayer != null) {
//add the KML layer to map using the UI thread
weakReferencedFragment.get().mActivity.runOnUiThread(() -> {
try {
kmlLayer.addLayerToMap();
} catch (Exception e) {
weakReferencedFragment.get().hideLoading();
TraceUtils.logException(e);
}
});
//zoom to the center of KML layer containers
new MoveMapToKMLLayer(weakReferencedFragment.get()).execute(kmlLayer);
}
}
}`
@sharkboy777 Could you please provide a sample KML file that you're having this problem with?
@sharkboy777 Could you please provide a sample KML file that you're having this problem with? https://drive.google.com/file/d/1sbNgwgLqdmKbJR3nnOxpp4ZTSa7DWRFl/view?usp=sharing
Here is the drive link for kml file... please give me a solution
@sharkboy777 Could you please provide a sample KML file that you're having this problem with? https://drive.google.com/file/d/1sbNgwgLqdmKbJR3nnOxpp4ZTSa7DWRFl/view?usp=sharing
Here is the drive link for kml file... please give me a solution
any update on this??
Got anything on this issue?? Or atleast before adding the kml layer onto the maps, is it possible to get renderer object, to parse the KML data and get the polygons?
Why because, right now it seems to be not possible to get the renderer object before adding the KML layer onto maps.
@sharkboy777 I haven't had time to look at this
I CPU profiled loading this KML and the bottleneck is calling GoogleMap.addPolygon()
. It calls the method 9377 times, since there's so many polygons in the 20 KMLs embedded in this single KML. Google Maps on the web won't even load KMLs over 5MB, so I couldn't compare the performance there. Google Earth does do a good job loading and displaying this KML in a web browser fairly quickly though. Any performance optimization for loading this KML on Android would have to be done in the GoogleMap
addPolygon()
method, which isn't part of the android-maps-utils library.
I'd suggest splitting this KML into 20 smaller KMLs that can be loaded and displayed individually. Even if you display them all at once, you could at least add them to the map on separate main thread run loops to avoid freezing the UI for as long.
I CPU profiled loading this KML and the bottleneck is calling
GoogleMap.addPolygon()
. It calls the method 9377 times, since there's so many polygons in the 20 KMLs embedded in this single KML. Google Maps on the web won't even load KMLs over 5MB, so I couldn't compare the performance there. Google Earth does do a good job loading and displaying this KML in a web browser fairly quickly though. Any performance optimization for loading this KML on Android would have to be done in theGoogleMap
addPolygon()
method, which isn't part of the android-maps-utils library.I'd suggest splitting this KML into 20 smaller KMLs that can be loaded and displayed individually. Even if you display them all at once, you could at least add them to the map on separate main thread run loops to avoid freezing the UI for as long.
afdfd
I CPU profiled loading this KML and the bottleneck is calling
GoogleMap.addPolygon()
. It calls the method 9377 times, since there's so many polygons in the 20 KMLs embedded in this single KML. Google Maps on the web won't even load KMLs over 5MB, so I couldn't compare the performance there. Google Earth does do a good job loading and displaying this KML in a web browser fairly quickly though. Any performance optimization for loading this KML on Android would have to be done in theGoogleMap
addPolygon()
method, which isn't part of the android-maps-utils library.I'd suggest splitting this KML into 20 smaller KMLs that can be loaded and displayed individually. Even if you display them all at once, you could at least add them to the map on separate main thread run loops to avoid freezing the UI for as long.
-
The problem here is that, I can't even access the KML Layer object without rendering it on the map first(which already takes an ample amount of time). If I could do that then it will be easier for me to retrieve the polygons from each kml file and draw them on map without rendering the entire kml file on maps
-
There is no way for me to get 20 kml files instead of single kml file from the server. I will receive these single KML files(with more kmls in it) like above
-
Is there any way to get the KMLLayer or KMLRenderer object without actually rendering it on the maps first?
KmlLayer
is created before calling addLayerToMap()
, which adds the polygons to the map. Constructing KmlLayer
is also fairly long-running, as it takes a good amount of I/O and processing to parse such a large KML. Constructing the KmlLayer
can be done on a background thread though, avoiding blocking the UI. But addLayerToMap()
has to be called on the main thread, which is why it causes freezing to add such a large KML to the map.
If you're unable to edit the KML and break it up into multiple smaller files, I'd suggest still making sure you at least are constructing the KmlLayer
on a background thread. addLayerToMap()
has to be done on the main thread though.
For reference, I updated the KmlDemoActivity
to construct the KmlLayer
in the background in https://github.com/googlemaps/android-maps-utils/pull/607.
CPU profiling identifies GoogleMap.addPolygon()
as the bottleneck adding KmlLayer
to the map. Within this method, the bottleneck is ArrayList.sort()
, called in a couple places by Collections.sort()
.
The long-running KmlLayer.<init>
can all be done on a background thread. But the KmlLayer.addToMap()
has to be done on the main thread.
@jpoehnelt @arriolac hard to know exactly what could be optimized in the closed-source GoogleMap
code, but the GoogleMap.addPolygon()
method could likely be optimized significantly by utilizing a collection type that provides more efficient sorting or if somehow that sorting could be limited, avoided, or done off of the main thread.
@jeffdgr8 Have you tried profiling the library with the Android Maps v3 beta SDK? https://github.com/googlemaps/android-maps-utils/commits/android-sdk-v3-beta
We have a similar bottleneck for clustering when adding markers with Maps API v2, and slow performance adding markers was called out as fixed in the Android v3 beta SDK - see https://github.com/googlemaps/android-maps-utils/issues/164#issuecomment-549857232. Not sure if this fix also addresses slow performance adding polygons, but 🤞 if it was just a simple Collection sorting issue.
@barbeau I actually did pull the maps v3 branch to test and ran into this crash again on my Pixel Slate. I'll try profiling again on my phone. I also wanted to merge master into the android-sdk-v3-beta branch, which has conflicts.
I was happy to see that performance issue fixed in v3, as I was tracking it closely. There hasn't been much movement on the v3 beta since it was first announced last spring, not even an iterative beta release with that crash fixed.
I profiled with the maps v3 beta (https://github.com/googlemaps/android-maps-utils/pull/608) and actually couldn't get the KML to display on the map at all. The app hung for a few minutes with the main thread blocked and eventually crashed.
2020-01-28 15:45:03.596 13775-13816/com.google.maps.android.utils.demo E/System: java.lang.OutOfMemoryError: OutOfMemoryError thrown while trying to throw an exception; no stack trace available
2020-01-28 15:44:31.912 589-589/? A/libc: crash_dump helper failed to exec
2020-01-28 15:45:04.379 13775-13882/? E/AndroidRuntime: Error reporting crash
java.lang.OutOfMemoryError: OutOfMemoryError thrown while trying to throw OutOfMemoryError; no stack trace available
Other smaller KML files worked as expected.
@jeffdgr8 Thanks for checking that out. So is that actually a regression from Maps SDK v2? Would Maps SDK v2 eventually load if you gave it enough time?
@barbeau yes, with the v2 SDK it takes 10-15 seconds to add the polygons and display on the map. So this is a regression in v3. I created a bug report.
KmlLayer
is created before callingaddLayerToMap()
, which adds the polygons to the map. ConstructingKmlLayer
is also fairly long-running, as it takes a good amount of I/O and processing to parse such a large KML. Constructing theKmlLayer
can be done on a background thread though, avoiding blocking the UI. ButaddLayerToMap()
has to be called on the main thread, which is why it causes freezing to add such a large KML to the map.If you're unable to edit the KML and break it up into multiple smaller files, I'd suggest still making sure you at least are constructing the
KmlLayer
on a background thread.addLayerToMap()
has to be done on the main thread though.For reference, I updated the
KmlDemoActivity
to construct theKmlLayer
in the background in #607.
yes.. for now i am getting the kmllayer object on a background thread and then adding the layertomap using main ui thread.
There is another issue in this same kml file, which is it doesn't load the styles but just loads the plain black polygon lines without any fill colors. Raised this issue in the below ticket. https://github.com/googlemaps/android-maps-utils/issues/583
Because of the above issue, I had to get all polygon objects from the rendered kmllayer and draw them on maps again using polygon styles to get the output. I don't know exactly if it is the issue with map-utils library or the kml file itself
@barbeau yes, with the v2 SDK it takes 10-15 seconds to add the polygons and display on the map. So this is a regression in v3. I created a bug report.
@jeffdgr8 , @barbeau Thank you guys for helping out with the issue and reporting it to google. Hope they fix it soon😊😊
This issue has been automatically marked as stale because it has not had recent activity. Please comment here if it is still valid so that we can reprioritize. Thank you!
Not stale.
This issue has been automatically marked as stale because it has not had recent activity. Please comment here if it is still valid so that we can reprioritize. Thank you!
Not stale.
This issue has been automatically marked as stale because it has not had recent activity. Please comment here if it is still valid so that we can reprioritize. Thank you!
Not stale
Still useful
This issue has been automatically marked as stale because it has not had recent activity. Please comment here if it is still valid so that we can reprioritize. Thank you!
Not stale
This issue has been automatically marked as stale because it has not had recent activity. Please comment here if it is still valid so that we can reprioritize. Thank you!
Closing this. Please reopen if you believe it should be addressed. Thank you for your contribution.
Not Stale, Still m facing this issue with latest sdk in 2024