'Android Google map Cluster Item marker with dynamic image URL - overwrite URL with all marker

In my app having cluster on map, Top/Main cluster marker show total marker count, click on that show all sub cluster item marker.

In Cluster item(Sub cluster marker) show round background with different colour and in between that show image from the URL ( get from the web service response), cluster item show image properly but my issue is that after refreshing last response image URL overwrite with all marker image, means all cluster item show same image instead of different one.

Please any one can help to this overwrite issue. my code is following.

      private class RenderClusterInfoWindow extends DefaultClusterRenderer<ModelClusterBikeList> {

    private final IconGenerator mClusterIconGenerator = new IconGenerator(getActivity());
    private final IconGenerator iconGenerator = new IconGenerator(getActivity());
    ImageView imageView;
    int markerWidth;
    int markerHeight;
    private DisplayImageOptions options;

    RenderClusterInfoWindow(Activity context, GoogleMap map, ClusterManager<ModelClusterBikeList> clusterManager) {
        super(context, map, clusterManager);

        // Main inflate view it show number data available inside cluster
        View multiProfile = getLayoutInflater().inflate(R.layout.inflate_cluster, null);
        mClusterIconGenerator.setContentView(multiProfile);

        markerWidth = (int) context.getResources().getDimension(R.dimen.custom_profile_image);
        markerHeight = (int) context.getResources().getDimension(R.dimen.custom_profile_image);

        // inflator its show image from the response url. (cluster item)
        View clusterITEM = getLayoutInflater().inflate(R.layout.inflate_cluster_item, null);
        iconGenerator.setContentView(clusterITEM);
        imageView = clusterITEM.findViewById(R.id.imageClusterPIN);


        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(markerWidth, markerHeight);
        layoutParams.gravity = Gravity.CENTER;
        imageView.setLayoutParams(layoutParams);


        ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(getActivity()));

        options = new DisplayImageOptions.Builder()
                .showImageForEmptyUri(R.mipmap.image_icn)
                .showImageOnFail(R.mipmap.image_icn)
                .cacheInMemory(false)
                .cacheOnDisk(true)
                .considerExifParams(true)
                .bitmapConfig(Bitmap.Config.RGB_565)
                .build();
    }

    @Override
    protected boolean shouldRenderAsCluster(Cluster<ModelClusterBikeList> cluster) {

        if (getActivity() != null) {
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (googleMap.getCameraPosition().zoom > 19.0) {
                        setClusterSize = 2;
                    } else {
                        setClusterSize = 4;
                    }
                }
            });
        }

        if (setClusterSize == 2) {
            return cluster.getSize() > cluster.getSize();
        } else {
            return cluster.getSize() > setClusterSize;
        }

    }

    @Override
    protected void onClusterRendered(Cluster<ModelClusterBikeList> cluster, Marker marker) {
        super.onClusterRendered(cluster, marker);
    }

    @Override
    protected void onBeforeClusterItemRendered(ModelClusterBikeList item, MarkerOptions markerOptions) {


        iconGenerator.setBackground(
                ContextCompat.getDrawable(getActivity(), R.drawable.round_asset));


        ImageLoader.getInstance().displayImage(item.getAssets_img_url(), imageView, options);

        // Issue is here , overwrite image url here with all marker./cluster item.
        Bitmap icon = iconGenerator.makeIcon(item.getAssets_img_url());
        markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));

        markerOptions.title(item.getId());
        markerOptions.draggable(true);

        super.onBeforeClusterItemRendered(item, markerOptions);
    }

    @Override
    protected void onBeforeClusterRendered(Cluster<ModelClusterBikeList> cluster, MarkerOptions markerOptions) {

        mClusterIconGenerator.setBackground(null);
        Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
        markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));

    }

    @Override
    protected void onClusterItemRendered(ModelClusterBikeList clusterItem, Marker marker) {
        super.onClusterItemRendered(clusterItem, marker);
    }
}

I also try with putting all code of "onBeforeClusterItemRendered" into onClusterItemRendered but getting same result, same overwrite last url with all cluter item.



Solution 1:[1]

Hello @Topsy change code as per folloding it will work for you.

First replace onBeforeClusterItemRendered method with following code.

   @Override
   protected void onBeforeClusterItemRendered(ModelClusterBikeList item, MarkerOptions 
   markerOptions) {

        icon = iconGenerator.makeIcon();
        markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon)).
                                                      title(item.getAssets_img_url());

        markerOptions.title(item.getId());
        markerOptions.draggable(true);

        super.onBeforeClusterItemRendered(item, markerOptions);
   }

and then replace onClusterItemRendered method with following code.

   @Override
   protected void onClusterItemRendered(ModelClusterBikeList clusterItem, Marker 
   marker) {


     if (getActivity() != null) {

         Glide.with(getActivity())
              .asBitmap()
              .load(clusterItem.getAssets_img_url())
              .error(R.drawable.ic_launcher)
              .diskCacheStrategy(DiskCacheStrategy.ALL)
              .into(new CustomTarget<Bitmap>() {
               @Override
               public void onResourceReady(@NonNull Bitmap resource, @Nullable 
               Transition<? super Bitmap> transition) {

                   try {
                      if (googleMap != null) {

                            iconGenerator.setBackground(
                            ContextCompat.getDrawable(getActivity(), 
                                                        R.drawable.round_asset));

                            imageView.setImageBitmap(resource);
                            imageView.buildDrawingCache();
                            Bitmap icon = iconGenerator.makeIcon();
                             if (icon != null) {
                             marker.setIcon(BitmapDescriptorFactory.fromBitmap(icon));
                           }
                         }
                     } catch (Exception e) {
                              e.printStackTrace();
                      }
                 }

                @Override
                public void onLoadCleared(@Nullable Drawable placeholder) {
                }
            });
          }

      }

Solution 2:[2]

This is an updated solution that makes use of Kotlin, Coroutine and Coil:

class Custom(
    private val coroutineScope: CoroutineScope,
    private val context: Context,
    private val map: GoogleMap,
    clusterManager: ClusterManager<CustomMapItem>?,
) : DefaultClusterRenderer<CustomMapItem>(context, map, clusterManager), GoogleMap.OnCameraIdleListener {
    var itemId: String? = null
    private val iconFactory = IconGenerator(context)
    private var currentZoomLevel = 0f
    private var maxZoomLevel = 0f

    /**
     * Method called right after the cluster item (the marker) is rendered.
     * This is where properties for the Marker object should be set.
     */
    override fun onClusterItemRendered(clusterItem: CustomMapItem, marker: Marker) {
        super.onClusterItemRendered(clusterItem, marker)
        marker.tag = clusterItem
        coroutineScope.launch {
            val drawable: Drawable = checkNotNull(
                context.imageLoader.execute(
                    ImageRequest.Builder(context)
                        .data(clusterItem.item.imageUrl)
                        .fallback(R.drawable.ui_img_default_profile)
                        .error(R.drawable.ui_img_default_profile)
                        .diskCachePolicy(CachePolicy.ENABLED)
                        .allowHardware(false)
                        .build(),
                ).drawable,
            )
            val imageView = ImageView(context).apply {
                setImageDrawable(drawable)
                scaleType = ImageView.ScaleType.CENTER_CROP
                layoutParams = ViewGroup.LayoutParams(PROFILE_PICTURE_SIZE_IN_DP.toPxSize, PROFILE_PICTURE_SIZE_IN_DP.toPxSize)
            }
            iconFactory.setContentView(imageView)
            marker.setIcon(BitmapDescriptorFactory.fromBitmap(iconFactory.makeIcon()))
            if (clusterItem.item.id == itemId) {
                marker.showInfoWindow()
            }
        }
    }

    override fun onCameraIdle() {
        currentZoomLevel = map.cameraPosition.zoom
        maxZoomLevel = map.maxZoomLevel
    }

    override fun shouldRenderAsCluster(cluster: Cluster<CustomMapItem>): Boolean {
        // Detect overlapped ege case
        if (currentZoomLevel >= maxZoomLevel - 1 && cluster.size > 1) {
            var zIndex = 1
            for (item in cluster.items) {
                item.zIndex = zIndex++
            }
        }
        return currentZoomLevel < maxZoomLevel - 1 && cluster.size > 1
    }

    companion object {
        private const val PROFILE_PICTURE_SIZE_IN_DP = 48
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Nirav Mehta
Solution 2 Roberto Leinardi