如何在具有边界框限制的 google 地图中管理超过 1000 个自定义标记以避免内存不足异常?
How to manage more than 1000 custom markers in google map with bounding box limitation to avoid Out of memory exception?
我在我的项目中使用带有自定义标记的 google 地图,
每个标记需要使用自定义视图进行设置,用于不同的目的,例如 waypoints 使用折线和标记来识别它们,使用标记的多边形等。
现在当这些标记超过1000个时,位图无法加载到Map中并抛出OOM。
我使用矢量绘图作为标记标识和普通文本视图来调平它们,创建位图采用 180*210 图像,
如何在不出现滞后和 OOM 问题的情况下进行高效管理?
这是代码:
这是从 allGlobalPoints 数组中读取位置并区分它们并绘制它们。
mMap.clear();
allpointPlotterThreadRunning = true;
switchTospecific = true;
final String POINTS = "points";
final String POIS = "pois";
final String FAILSAFE = "failsafe";
final String POLYGON = "polygon";
final String LASTPOLYGON = "lastpolygon";
allMapPointPlotter = new AsyncTask<Void, Object, Void>() {
ProgressDialog pgbarLoading;
PolylineOptions polyline;
PolygonOptions plogon;
@Override
protected void onPreExecute() {
super.onPreExecute();
final View tiltleView = ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.progress_dialog_title_background, null);
OpenSansRegularTextView tiltle = (OpenSansRegularTextView) tiltleView.findViewById(R.id.title_text);
tiltle.setText("UAV Editor");
pgbarLoading = new ProgressDialog(getActivity());
pgbarLoading.setCancelable(false);
pgbarLoading.setMessage("" + getActivity().getString(R.string.please_wait));
pgbarLoading.setCustomTitle(tiltleView);
pgbarLoading.show();
markerPlottedList = new ArrayList<>();
markerOnQueue = new ArrayList<>();
((DashboardActivity) getActivity()).setZoomOut();
}
@Override
protected void onCancelled() {
super.onCancelled();
allpointPlotterThreadRunning = false;
}
@Override
protected Void doInBackground(Void... voids) {
try {
if (allpointPlotterThreadRunning) {
if (allGlobalPoints.size() > 0) {
for (int global = 0; global < allGlobalPoints.size(); global++) {
if (allpointPlotterThreadRunning) {
//getting first object containing all points data
AllGlobalPointsArrayData globalDataObject = allGlobalPoints.get(global); //This is the object of the position that contains all 5 data
if (globalDataObject.getPointsDataArray() != null && globalDataObject.getPointsDataArray().size() > 0) {
ArrayList<RoutePointCoordinatesDataType> innerarraylist = globalDataObject.getPointsDataArray();
for (int i = 0; i < innerarraylist.size(); i++) {
if (allpointPlotterThreadRunning) {
if (i == (innerarraylist.size() - 1)) {
publishProgress(
POINTS,
Double.parseDouble(innerarraylist.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerarraylist.get(i).getCoordinatesLongitude()),
i,
"" + innerarraylist.get(i).getTag(),
innerarraylist.get(i).getHeadingAngle(),
true
);
} else {
publishProgress(
POINTS,
Double.parseDouble(innerarraylist.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerarraylist.get(i).getCoordinatesLongitude()),
i,
"" + innerarraylist.get(i).getTag(),
innerarraylist.get(i).getHeadingAngle(),
false
);
}
} else {
break;
}
}
}
if (globalDataObject.getPoiDataArray() != null && globalDataObject.getPoiDataArray().size() > 0) {
ArrayList<RoutePointCoordinatesDataType> innerList = globalDataObject.getPoiDataArray();
if (innerList != null && innerList.size() > 0) {
for (int i = 0; i < innerList.size(); i++) {
if (allpointPlotterThreadRunning) {
publishProgress(
POIS,
Double.parseDouble(innerList.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerList.get(i).getCoordinatesLongitude()),
i,
"" + innerList.get(i).getTag()
);
} else {
break;
}
}
}
}
if (globalDataObject.getFailsafeDataArray() != null && globalDataObject.getFailsafeDataArray().size() > 0) {
ArrayList<RoutePointCoordinatesDataType> innerArray = globalDataObject.getFailsafeDataArray();
if (innerArray != null && innerArray.size() > 0) {
for (int i = 0; i < innerArray.size(); i++) {
if (allpointPlotterThreadRunning) {
publishProgress(
FAILSAFE,
Double.parseDouble(innerArray.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerArray.get(i).getCoordinatesLongitude()),
i,
"" + innerArray.get(i).getTag()
);
} else {
break;
}
}
}
}
if (globalDataObject.getPolygonLastUsedDataArray() != null && globalDataObject.getPolygonLastUsedDataArray().size() > 0) {
ArrayList<RoutePointCoordinatesDataType> innerArray = globalDataObject.getPolygonLastUsedDataArray();
if (innerArray != null && innerArray.size() > 0) {
for (int i = 0; i < innerArray.size(); i++) {
if (allpointPlotterThreadRunning) {
if (i == (innerArray.size() - 1)) {
publishProgress(
LASTPOLYGON,
Double.parseDouble(innerArray.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerArray.get(i).getCoordinatesLongitude()),
i,
"" + innerArray.get(i).getTag(),
true
);
} else {
publishProgress(
LASTPOLYGON,
Double.parseDouble(innerArray.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerArray.get(i).getCoordinatesLongitude()),
i,
"" + innerArray.get(i).getTag(),
false
);
}
} else {
break;
}
}
}
}
if (globalDataObject.getPolygonLastUsedDataArray() == null || globalDataObject.getPolygonLastUsedDataArray().size() == 0) {
ArrayList<RoutePointCoordinatesDataType> innerArray = globalDataObject.getPolygonDataArray();
if (innerArray != null && innerArray.size() > 0) {
for (int i = 0; i < innerArray.size(); i++) {
if (allpointPlotterThreadRunning) {
if (i == (innerArray.size() - 1)) {
publishProgress(
POLYGON,
Double.parseDouble(innerArray.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerArray.get(i).getCoordinatesLongitude()),
i,
"" + innerArray.get(i).getTag(),
true
);
} else {
publishProgress(
POLYGON,
Double.parseDouble(innerArray.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerArray.get(i).getCoordinatesLongitude()),
i,
"" + innerArray.get(i).getTag(),
false
);
}
} else {
break;
}
}
}
}
} else {
break;
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(Object... values) {
super.onProgressUpdate(values);
if (allpointPlotterThreadRunning) {
String tagmarker = (String) values[0];
int innerCounter = (Integer) values[3];
if (tagmarker.equalsIgnoreCase(POINTS)) {
if (innerCounter == 0) {
polyline = new PolylineOptions();
polyline.width(4);
polyline.color(Color.parseColor("#425fa9"));
polyline.geodesic(true);
}
polyline.add(
new LatLng(
(Double) values[1],
(Double) values[2]
)
);
if ((Double) values[5] != 400) {
createMarker(
mMap,
(Double) values[1],
(Double) values[2],
innerCounter,
(String) values[4],
(Double) values[5]
);
} else {
createMarker(
mMap,
(Double) values[1],
(Double) values[2],
innerCounter,
(String) values[4],
400
);
}
if ((Boolean) values[6]) {
mMap.addPolyline(polyline);
}
} else if (tagmarker.equalsIgnoreCase(POIS)) {
createMarkerPoi(
mMap,
(Double) values[1],
(Double) values[2],
innerCounter,
(String) values[4]
);
} else if (tagmarker.equalsIgnoreCase(FAILSAFE)) {
createMarkerFailsafe(
mMap,
(Double) values[1],
(Double) values[2],
innerCounter,
(String) values[4]
);
} else if (tagmarker.equalsIgnoreCase(POLYGON)) {
if (innerCounter == 0) {
plogon = new PolygonOptions();
plogon.fillColor(Color.parseColor("#20ff1a1a"));
plogon.strokeWidth((float) 5.1)
.strokeColor(Color.parseColor("#30ff1a1a"));
}
createMarkerPolygon(
mMap,
(Double) values[1],
(Double) values[2],
innerCounter,
(String) values[4]
);
plogon.add(new LatLng(
(Double) values[1],
(Double) values[2]
));
if ((Boolean) values[5]) {
mMap.addPolygon(plogon);
}
} else if (tagmarker.equalsIgnoreCase(LASTPOLYGON)) {
if (innerCounter == 0) {
plogon = new PolygonOptions();
plogon.fillColor(Color.parseColor("#20ff1a1a"));
plogon.strokeWidth((float) 5.1)
.strokeColor(Color.parseColor("#30ff1a1a"));
}
createMarkerPolygon(
mMap,
(Double) values[1],
(Double) values[2],
innerCounter,
(String) values[4]
);
plogon.add(new LatLng(
(Double) values[1],
(Double) values[2]
));
if ((Boolean) values[5]) {
mMap.addPolygon(plogon);
}
}
}
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
pgbarLoading.dismiss();
allpointPlotterThreadRunning = false;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
用于创建标记
和位图函数使用如下:->
memoryCacheData用作lrucache列表,用于快速访问位图
protected void createMarker(GoogleMap map, double latitude, double longitude, int inner, String outer, double angle) {
try {
Bitmap resultantBitmap = null;
if (((DashboardActivity) getActivity()).memoryCacheData != null && ((DashboardActivity) getActivity()).memoryCacheData.size() > 0) {
resultantBitmap = ((DashboardActivity) getActivity()).memoryCacheData.get(latitude + "/" + longitude + "-OwnTab-" + inner + "|" + outer);
if (resultantBitmap == null) {
resultantBitmap = getMarkerBitmapFromView("P" + (inner + 1), "P", angle);
((DashboardActivity) getActivity()).memoryCacheData.put(latitude + "/" + longitude + "-OwnTabMarker-" + inner + "|" + outer, resultantBitmap);
}
} else {
resultantBitmap = getMarkerBitmapFromView("P" + (inner + 1), "P", angle);
((DashboardActivity) getActivity()).memoryCacheData.put(latitude + "/" + longitude + "-OwnTabMarker-" + inner + "|" + outer, resultantBitmap);
}
map.addMarker(new MarkerOptions()
.position(new LatLng(latitude, longitude))
.anchor(0.5f, 0.5f)
.title("" + outer)
.icon(BitmapDescriptorFactory.fromBitmap(resultantBitmap))
);
} catch (Exception e) {
e.printStackTrace();
}
}
请帮助我如何在不冻结应用程序和避免内存不足异常的情况下管理位图,以及如何使用自定义视图管理这么多标记。
一次添加超过 1000 个标记不是一个好的做法。另一种方法是动态创建一个包含所有标记和 track/show 最近标记的数组。可以在这里找到类似的 question/response:google maps api find nearest markers
我知道回答这个问题为时已晚,但您可以使用 ClusterManager 以有效显示 1000 标记。首先将所有 lat long 放入 ArrayList 中,然后通过使用一次将列表添加到 ClusterManager mClusterManager.addItems(ArrayList<..>);, mClusterManager.cluster();.
这样做将消除 UI 冻结问题和内存不足问题。
为了实现 ClusterManager,请参考此 link:https://github.com/googlemaps/android-maps-utils/blob/master/demo/src/com/google/maps/android/utils/demo/CustomMarkerClusteringDemoActivity.java
我在我的项目中使用带有自定义标记的 google 地图, 每个标记需要使用自定义视图进行设置,用于不同的目的,例如 waypoints 使用折线和标记来识别它们,使用标记的多边形等。 现在当这些标记超过1000个时,位图无法加载到Map中并抛出OOM。
我使用矢量绘图作为标记标识和普通文本视图来调平它们,创建位图采用 180*210 图像,
如何在不出现滞后和 OOM 问题的情况下进行高效管理?
这是代码: 这是从 allGlobalPoints 数组中读取位置并区分它们并绘制它们。
mMap.clear();
allpointPlotterThreadRunning = true;
switchTospecific = true;
final String POINTS = "points";
final String POIS = "pois";
final String FAILSAFE = "failsafe";
final String POLYGON = "polygon";
final String LASTPOLYGON = "lastpolygon";
allMapPointPlotter = new AsyncTask<Void, Object, Void>() {
ProgressDialog pgbarLoading;
PolylineOptions polyline;
PolygonOptions plogon;
@Override
protected void onPreExecute() {
super.onPreExecute();
final View tiltleView = ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.progress_dialog_title_background, null);
OpenSansRegularTextView tiltle = (OpenSansRegularTextView) tiltleView.findViewById(R.id.title_text);
tiltle.setText("UAV Editor");
pgbarLoading = new ProgressDialog(getActivity());
pgbarLoading.setCancelable(false);
pgbarLoading.setMessage("" + getActivity().getString(R.string.please_wait));
pgbarLoading.setCustomTitle(tiltleView);
pgbarLoading.show();
markerPlottedList = new ArrayList<>();
markerOnQueue = new ArrayList<>();
((DashboardActivity) getActivity()).setZoomOut();
}
@Override
protected void onCancelled() {
super.onCancelled();
allpointPlotterThreadRunning = false;
}
@Override
protected Void doInBackground(Void... voids) {
try {
if (allpointPlotterThreadRunning) {
if (allGlobalPoints.size() > 0) {
for (int global = 0; global < allGlobalPoints.size(); global++) {
if (allpointPlotterThreadRunning) {
//getting first object containing all points data
AllGlobalPointsArrayData globalDataObject = allGlobalPoints.get(global); //This is the object of the position that contains all 5 data
if (globalDataObject.getPointsDataArray() != null && globalDataObject.getPointsDataArray().size() > 0) {
ArrayList<RoutePointCoordinatesDataType> innerarraylist = globalDataObject.getPointsDataArray();
for (int i = 0; i < innerarraylist.size(); i++) {
if (allpointPlotterThreadRunning) {
if (i == (innerarraylist.size() - 1)) {
publishProgress(
POINTS,
Double.parseDouble(innerarraylist.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerarraylist.get(i).getCoordinatesLongitude()),
i,
"" + innerarraylist.get(i).getTag(),
innerarraylist.get(i).getHeadingAngle(),
true
);
} else {
publishProgress(
POINTS,
Double.parseDouble(innerarraylist.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerarraylist.get(i).getCoordinatesLongitude()),
i,
"" + innerarraylist.get(i).getTag(),
innerarraylist.get(i).getHeadingAngle(),
false
);
}
} else {
break;
}
}
}
if (globalDataObject.getPoiDataArray() != null && globalDataObject.getPoiDataArray().size() > 0) {
ArrayList<RoutePointCoordinatesDataType> innerList = globalDataObject.getPoiDataArray();
if (innerList != null && innerList.size() > 0) {
for (int i = 0; i < innerList.size(); i++) {
if (allpointPlotterThreadRunning) {
publishProgress(
POIS,
Double.parseDouble(innerList.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerList.get(i).getCoordinatesLongitude()),
i,
"" + innerList.get(i).getTag()
);
} else {
break;
}
}
}
}
if (globalDataObject.getFailsafeDataArray() != null && globalDataObject.getFailsafeDataArray().size() > 0) {
ArrayList<RoutePointCoordinatesDataType> innerArray = globalDataObject.getFailsafeDataArray();
if (innerArray != null && innerArray.size() > 0) {
for (int i = 0; i < innerArray.size(); i++) {
if (allpointPlotterThreadRunning) {
publishProgress(
FAILSAFE,
Double.parseDouble(innerArray.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerArray.get(i).getCoordinatesLongitude()),
i,
"" + innerArray.get(i).getTag()
);
} else {
break;
}
}
}
}
if (globalDataObject.getPolygonLastUsedDataArray() != null && globalDataObject.getPolygonLastUsedDataArray().size() > 0) {
ArrayList<RoutePointCoordinatesDataType> innerArray = globalDataObject.getPolygonLastUsedDataArray();
if (innerArray != null && innerArray.size() > 0) {
for (int i = 0; i < innerArray.size(); i++) {
if (allpointPlotterThreadRunning) {
if (i == (innerArray.size() - 1)) {
publishProgress(
LASTPOLYGON,
Double.parseDouble(innerArray.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerArray.get(i).getCoordinatesLongitude()),
i,
"" + innerArray.get(i).getTag(),
true
);
} else {
publishProgress(
LASTPOLYGON,
Double.parseDouble(innerArray.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerArray.get(i).getCoordinatesLongitude()),
i,
"" + innerArray.get(i).getTag(),
false
);
}
} else {
break;
}
}
}
}
if (globalDataObject.getPolygonLastUsedDataArray() == null || globalDataObject.getPolygonLastUsedDataArray().size() == 0) {
ArrayList<RoutePointCoordinatesDataType> innerArray = globalDataObject.getPolygonDataArray();
if (innerArray != null && innerArray.size() > 0) {
for (int i = 0; i < innerArray.size(); i++) {
if (allpointPlotterThreadRunning) {
if (i == (innerArray.size() - 1)) {
publishProgress(
POLYGON,
Double.parseDouble(innerArray.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerArray.get(i).getCoordinatesLongitude()),
i,
"" + innerArray.get(i).getTag(),
true
);
} else {
publishProgress(
POLYGON,
Double.parseDouble(innerArray.get(i).getCoordinatesLatitude()),
Double.parseDouble(innerArray.get(i).getCoordinatesLongitude()),
i,
"" + innerArray.get(i).getTag(),
false
);
}
} else {
break;
}
}
}
}
} else {
break;
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(Object... values) {
super.onProgressUpdate(values);
if (allpointPlotterThreadRunning) {
String tagmarker = (String) values[0];
int innerCounter = (Integer) values[3];
if (tagmarker.equalsIgnoreCase(POINTS)) {
if (innerCounter == 0) {
polyline = new PolylineOptions();
polyline.width(4);
polyline.color(Color.parseColor("#425fa9"));
polyline.geodesic(true);
}
polyline.add(
new LatLng(
(Double) values[1],
(Double) values[2]
)
);
if ((Double) values[5] != 400) {
createMarker(
mMap,
(Double) values[1],
(Double) values[2],
innerCounter,
(String) values[4],
(Double) values[5]
);
} else {
createMarker(
mMap,
(Double) values[1],
(Double) values[2],
innerCounter,
(String) values[4],
400
);
}
if ((Boolean) values[6]) {
mMap.addPolyline(polyline);
}
} else if (tagmarker.equalsIgnoreCase(POIS)) {
createMarkerPoi(
mMap,
(Double) values[1],
(Double) values[2],
innerCounter,
(String) values[4]
);
} else if (tagmarker.equalsIgnoreCase(FAILSAFE)) {
createMarkerFailsafe(
mMap,
(Double) values[1],
(Double) values[2],
innerCounter,
(String) values[4]
);
} else if (tagmarker.equalsIgnoreCase(POLYGON)) {
if (innerCounter == 0) {
plogon = new PolygonOptions();
plogon.fillColor(Color.parseColor("#20ff1a1a"));
plogon.strokeWidth((float) 5.1)
.strokeColor(Color.parseColor("#30ff1a1a"));
}
createMarkerPolygon(
mMap,
(Double) values[1],
(Double) values[2],
innerCounter,
(String) values[4]
);
plogon.add(new LatLng(
(Double) values[1],
(Double) values[2]
));
if ((Boolean) values[5]) {
mMap.addPolygon(plogon);
}
} else if (tagmarker.equalsIgnoreCase(LASTPOLYGON)) {
if (innerCounter == 0) {
plogon = new PolygonOptions();
plogon.fillColor(Color.parseColor("#20ff1a1a"));
plogon.strokeWidth((float) 5.1)
.strokeColor(Color.parseColor("#30ff1a1a"));
}
createMarkerPolygon(
mMap,
(Double) values[1],
(Double) values[2],
innerCounter,
(String) values[4]
);
plogon.add(new LatLng(
(Double) values[1],
(Double) values[2]
));
if ((Boolean) values[5]) {
mMap.addPolygon(plogon);
}
}
}
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
pgbarLoading.dismiss();
allpointPlotterThreadRunning = false;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
用于创建标记 和位图函数使用如下:-> memoryCacheData用作lrucache列表,用于快速访问位图
protected void createMarker(GoogleMap map, double latitude, double longitude, int inner, String outer, double angle) {
try {
Bitmap resultantBitmap = null;
if (((DashboardActivity) getActivity()).memoryCacheData != null && ((DashboardActivity) getActivity()).memoryCacheData.size() > 0) {
resultantBitmap = ((DashboardActivity) getActivity()).memoryCacheData.get(latitude + "/" + longitude + "-OwnTab-" + inner + "|" + outer);
if (resultantBitmap == null) {
resultantBitmap = getMarkerBitmapFromView("P" + (inner + 1), "P", angle);
((DashboardActivity) getActivity()).memoryCacheData.put(latitude + "/" + longitude + "-OwnTabMarker-" + inner + "|" + outer, resultantBitmap);
}
} else {
resultantBitmap = getMarkerBitmapFromView("P" + (inner + 1), "P", angle);
((DashboardActivity) getActivity()).memoryCacheData.put(latitude + "/" + longitude + "-OwnTabMarker-" + inner + "|" + outer, resultantBitmap);
}
map.addMarker(new MarkerOptions()
.position(new LatLng(latitude, longitude))
.anchor(0.5f, 0.5f)
.title("" + outer)
.icon(BitmapDescriptorFactory.fromBitmap(resultantBitmap))
);
} catch (Exception e) {
e.printStackTrace();
}
}
请帮助我如何在不冻结应用程序和避免内存不足异常的情况下管理位图,以及如何使用自定义视图管理这么多标记。
一次添加超过 1000 个标记不是一个好的做法。另一种方法是动态创建一个包含所有标记和 track/show 最近标记的数组。可以在这里找到类似的 question/response:google maps api find nearest markers
我知道回答这个问题为时已晚,但您可以使用 ClusterManager 以有效显示 1000 标记。首先将所有 lat long 放入 ArrayList 中,然后通过使用一次将列表添加到 ClusterManager mClusterManager.addItems(ArrayList<..>);, mClusterManager.cluster();.
这样做将消除 UI 冻结问题和内存不足问题。
为了实现 ClusterManager,请参考此 link:https://github.com/googlemaps/android-maps-utils/blob/master/demo/src/com/google/maps/android/utils/demo/CustomMarkerClusteringDemoActivity.java