Justin
Justin

Reputation: 4520

Android Google map show custom marker and clustering issue

I would like to show the custom marker to google map and cluster them. The marker contains a ImageView that will shows the avatar that is downloaded from network. Here is my target:
enter image description here

Everythings are OK, however, when I implemented the Google Maps Android Marker Clustering Utility, the ImageView shows the same avatar (sometime two wrong avatars). enter image description here
Here is my custom MarkerRender:

public class MarkerRender extends DefaultClusterRenderer<Image> {
    private static final String TAG = MarkerRender.class.getSimpleName();
    private IconGenerator clusterGenerator;
    private IconGenerator markerGenerator;
    private ImageView mImgMarkerThumbnail;
    private ImageView mImgMarkerClusterThumbnail;
    private TextView txtSizeCluster;
    private Activity activity;
    private Bitmap mask, background;
    private AtomicInteger imageDownloadCounter;
    private int totalItem;
    private ImageSize imageSize;

    public MarkerRender(FragmentActivity activity, GoogleMap mMap, ClusterManager<Image> mClusterManager) {
        super(activity, mMap, mClusterManager);
        this.activity = activity;
        imageDownloadCounter = new AtomicInteger(0);
        mask = BitmapFactory.decodeResource(activity.getResources(),
                R.drawable.annotation_behind);
        background = BitmapFactory.decodeResource(activity.getResources(),
                R.drawable.annotation_behind);
        setUpClusterIcon();
        setUpMarker();
    }

    private void setUpClusterIcon() {
        clusterGenerator = new IconGenerator(activity);
        View clusterView = activity.getLayoutInflater().inflate(R.layout.custom_marker_cluster, null);
        txtSizeCluster = (TextView) clusterView.findViewById(R.id.tv_number_marker);
        mImgMarkerClusterThumbnail = (ImageView) clusterView.findViewById(R.id.img_load);
        clusterGenerator.setContentView(clusterView);
        clusterGenerator.setBackground(null);
    }

    private void setUpMarker() {
        markerGenerator = new IconGenerator(activity);
        View markerView = activity.getLayoutInflater().inflate(R.layout.custom_marker, null);
        mImgMarkerThumbnail = (ImageView) markerView.findViewById(R.id.img_load);
        markerGenerator.setContentView(markerView);
        markerGenerator.setBackground(null);

    }

    @Override
    protected void onBeforeClusterItemRendered(final Image image, final MarkerOptions markerOptions) {
        initImageSizeIfNeed();
        Bitmap icon = markerGenerator.makeIcon();
        PFLogManager.INSTANCE.logE(TAG, "maken icon: " + icon.hashCode());
        markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
        icon.recycle();
    }

    @Override
    protected void onClusterItemRendered(final Image image, Marker marker) {
        super.onClusterItemRendered(image, marker);
        ImageLoader.getInstance().loadImage(image.getMapImageLink(), imageSize,
                new SimpleImageLoadingListener() {
                    @Override
                    public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                        Bitmap croppedBitmap = Helpers.makeCroppedBitmap(loadedImage, background, mask);
                        mImgMarkerThumbnail.setImageBitmap(croppedBitmap);
                    }
                });
    }

    @Override
    protected void onBeforeClusterRendered(Cluster<Image> cluster, MarkerOptions markerOptions) {
        initImageSizeIfNeed();
        Bitmap icon = clusterGenerator.makeIcon();
        markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
        icon.recycle();
    }

    @Override
    protected void onClusterRendered(Cluster<Image> cluster, Marker marker) {
        super.onClusterRendered(cluster, marker);
        ArrayList<Image> list = new ArrayList<>(cluster.getItems());
        setTextNumberMarker(cluster);
        String urlFirstImage = list.get(0).getMapImageLink();
        ImageLoader.getInstance().loadImage(urlFirstImage, imageSize,
                new SimpleImageLoadingListener() {
                    @Override
                    public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                        final Bitmap croppedBitmap = Helpers.makeCroppedBitmap(loadedImage, background, mask);
                        mImgMarkerClusterThumbnail.setImageBitmap(croppedBitmap);
                    }
                });
    }

    private void loadClusterThumbnail(String url) {
    }

    private void setTextNumberMarker(Cluster<Image> cluster) {
        int size = cluster.getSize();
        if (size > 99) {
            txtSizeCluster.setText("99+");
        } else {
            txtSizeCluster.setText(String.valueOf(cluster.getSize()));
        }
    }

    @Override
    protected boolean shouldRenderAsCluster(Cluster cluster) {
        return cluster.getSize() > 1;
    }
}

I've guess that the issue is I use only one ImageView to show those avatar, so I try to use unique ImageView for each marker (by inflat new one from xml every time needed), but the result is they are all show the blank marker (just the background and there is no avatar).

Upvotes: 4

Views: 3218

Answers (1)

Justin
Justin

Reputation: 4520

I've resolved it myself. My solution is use the Marker.setIcon() method after the image is downloaded from netword or got from cache. I dont use the ImageView anymore.
So, i modified the above MarkerRender class:
The setUpClusterIcon() method:

private void setUpClusterIcon() {
    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(markerWidth, markerHeight);
    ImageView marker = new ImageView(activity);
    marker.setLayoutParams(params);

    clusterGenerator = new IconGenerator(activity);
    clusterGenerator.setContentView(marker);
    clusterGenerator.setBackground(null);
}


And the onClusterItemRendered() method:

 protected void onClusterItemRendered(final Image image, final Marker marker) {
        super.onClusterItemRendered(image, marker);
        ImageLoader.getInstance().loadImage(image.getMapImageLink(), imageSize,
                new SimpleImageLoadingListener() {
                    @Override
                    public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                        Bitmap croppedBitmap = Helpers.makeClusterItemBitmap(background, loadedImage, mask);
                        try {
                            marker.setIcon(BitmapDescriptorFactory.fromBitmap(croppedBitmap));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });
    }


Also the makeClusterItemBitmap helper method:

   public static Bitmap makeClusterItemBitmap(Bitmap background, Bitmap original, Bitmap mask) {
        Bitmap croppedOriginal = makeCroppedBitmap(original, mask);
        Bitmap result = Bitmap.createBitmap(background.getWidth(), background.getHeight(),
                Bitmap.Config.ARGB_8888);
        Canvas mCanvas = new Canvas(result);
        croppedOriginal = Bitmap.createScaledBitmap(croppedOriginal, croppedOriginal.getWidth() - 20, croppedOriginal.getHeight() - 20, true);
        mCanvas.drawBitmap(background, 0, 0, null);
        mCanvas.drawBitmap(croppedOriginal, 10, 10, null);
        return result;
    }

    public static Bitmap makeCroppedBitmap(Bitmap original, Bitmap mask) {
        original = Bitmap.createScaledBitmap(original, mask.getWidth(),
                mask.getHeight(), true);
        Bitmap result = Bitmap.createBitmap(original.getWidth(), original.getHeight(),
                Bitmap.Config.ARGB_8888);
        Canvas mCanvas = new Canvas(result);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        mCanvas.drawBitmap(original, 0, 0, null);
        mCanvas.drawBitmap(mask, 0, 0, paint);
        paint.setXfermode(null);
        return result;
    }


Done, finish three nightmare researchingdays days :P
However, this approach leads new issue: the performance. Cause by drawing new bitmap with many layers, the map is laggy a bit. I'm thinking in improving this :)
Any sugguestion are appriciate :D

Upvotes: 4

Related Questions