Я пытаюсь реализовать кластер Google Map, следуя примерам в библиотеке android-map-utils (https://github.com/googlemaps/android-maps-utils). Разница в том, что я хочу загрузить изображения с некоторых URL-адресов. Я использую библиотеку Glide для этой задачи.
Это мой пользовательский ClusterRenderer:
class MapClusterRenderer extends DefaultClusterRenderer<MapClusterItem> {
private static final int MAX_IMAGES_IN_CLUTER = 4;
private static final int MIN_ITEMS_TO_RENDER_AS_CLUSTER = 2;
private Context context;
private int imageDimension;
private IconGenerator itemIconGenerator;
private ImageView itemImageView;
private IconGenerator clusterIconGenerator;
private ImageView clusterImageView;
public MapClusterRenderer(Context context, GoogleMap googleMap, ClusterManager<MapClusterItem> clusterManager) {
super(context, googleMap, clusterManager);
this.context = context;
imageDimension = (int) context.getResources().getDimension(R.dimen.image_xsm);
int padding = (int) context.getResources().getDimension(R.dimen.cluster_marker_padding);
itemImageView = new ImageView(context);
itemImageView.setLayoutParams(new ViewGroup.LayoutParams(imageDimension, imageDimension));
itemImageView.setPadding(padding, padding, padding, padding);
itemIconGenerator = new IconGenerator(context);
itemIconGenerator.setContentView(itemImageView);
View clusterMarkerView = View.inflate(context, R.layout.item_cluster_marker, null);
clusterImageView = clusterMarkerView.findViewById(R.id.images);
clusterIconGenerator = new IconGenerator(context);
clusterIconGenerator.setContentView(clusterMarkerView);
}
@Override
protected void onBeforeClusterItemRendered(MapClusterItem mapClusterItem, MarkerOptions markerOptions) {
markerOptions.visible(false);
}
@Override
protected void onBeforeClusterRendered(Cluster<MapClusterItem> cluster, MarkerOptions markerOptions) {
markerOptions.visible(false);
}
@Override
protected void onClusterItemRendered(MapClusterItem mapClusterItem, Marker marker) {
Glide.with(context)
.load(mapClusterItem.getEstablishment().getImageUrl())
.into(new CustomTarget<Drawable>(imageDimension, imageDimension) {
@Override
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
itemImageView.setImageDrawable(resource);
Bitmap bitmap = itemIconGenerator.makeIcon();
marker.setIcon(BitmapDescriptorFactory.fromBitmap(bitmap));
marker.setVisible(true);
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
}
});
}
@Override
protected void onClusterRendered(Cluster<MapClusterItem> cluster, Marker marker) {
Thread thread = new Thread(() -> {
List<FutureTarget<Drawable>> futures = new ArrayList<>();
LatLngBounds.Builder boundsBuilder = new LatLngBounds.Builder();
for (MapClusterItem mapClusterItem : cluster.getItems()) {
if (futures.size() < MAX_IMAGES_IN_CLUTER) {
FutureTarget<Drawable> future = Glide.with(context)
.load(mapClusterItem.getEstablishment().getImageUrl())
.submit(imageDimension, imageDimension);
futures.add(future);
}
boundsBuilder.include(mapClusterItem.getLatLng());
}
List<Drawable> drawables = new ArrayList<>();
for (FutureTarget<Drawable> future : futures) {
try {
drawables.add(future.get());
} catch (ExecutionException | InterruptedException e) {
Timber.e(e, "Error downloading establishment image. Drawing cluster without this image...");
}
}
Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> {
MultiDrawable multiDrawable = new MultiDrawable(drawables);
multiDrawable.setBounds(0, 0, imageDimension, imageDimension);
clusterImageView.setImageDrawable(multiDrawable);
Bitmap bitmap = clusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
marker.setIcon(BitmapDescriptorFactory.fromBitmap(bitmap));
marker.setPosition(boundsBuilder.build().getCenter());
marker.setVisible(true);
});
});
thread.start();
}
@Override
protected boolean shouldRenderAsCluster(Cluster cluster) {
return cluster.getSize() >= MIN_ITEMS_TO_RENDER_AS_CLUSTER;
}
}
Поскольку я использую Glide, мне нужно создать фоновый поток для асинхронной загрузки всех изображений с помощью метода Glide.submit, который возвращает объект Future.
for (MapClusterItem mapClusterItem : cluster.getItems()) {
if (futures.size() < MAX_IMAGES_IN_CLUTER) {
FutureTarget<Drawable> future = Glide.with(context)
.load(mapClusterItem.getEstablishment().getImageUrl())
.submit(imageDimension, imageDimension);
futures.add(future);
}
boundsBuilder.include(mapClusterItem.getLatLng());
}
Тогда я жду всех будущих результатов, чтобы получить его пригодные для рисования.
List<Drawable> drawables = new ArrayList<>();
for (FutureTarget<Drawable> future : futures) {
try {
drawables.add(future.get());
} catch (ExecutionException | InterruptedException e) {
Timber.e(e, "Error downloading establishment image. Drawing cluster without this image...");
}
}
Не нужно рисовать кластер в потоке пользовательского интерфейса точно так же, как в примере с android-map-utils.
Handler handler = new Handler(Looper.getMainLooper());
handler.post(() -> {
MultiDrawable multiDrawable = new MultiDrawable(drawables);
multiDrawable.setBounds(0, 0, imageDimension, imageDimension);
clusterImageView.setImageDrawable(multiDrawable);
Bitmap bitmap = clusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
marker.setIcon(BitmapDescriptorFactory.fromBitmap(bitmap));
marker.setPosition(boundsBuilder.build().getCenter());
marker.setVisible(true);
});
Проблема в том, что этот код генерирует пустой маркер кластера с установленным размером кластера.
Отладка этого кода Я видел, что изображения загружаются правильно, но когда вызывается метод MultiDrawable.draw
, рисованные элементы не печатаются правильно на холсте.
Это все чертежи, загруженные в экземпляр MultiDrawable:
Это загружаемое растровое изображение:
Это холст результата:
Что я делаю не так? Я проверил много примеров, и я не могу найти проблему.