Kali Aney Kali Aney - 10 days ago 9
Android Question

Android : how to reload custom markers once the image is downloaded via Picasso?

I'm trying to load dynamically users avatars as custom markers. I based my code on the google maps utils demo, but somehow it doesn't work, it loads only one image and all the others are empty:

enter image description here

Here is my code:

public class MapsActivity extends FragmentActivity implements ClusterManager.OnClusterItemClickListener<ModelUser>, ClusterManager.OnClusterItemInfoWindowClickListener<ModelUser> {

private ClusterManager<ModelUser> mClusterManager;
private GoogleMap mMap; // Might be null if Google Play services APK is not available.
private QueryAPI query = new QueryAPI();
private List<ModelUser> users = new ArrayList<ModelUser>();
ImageLoader imageLoader = AppController.getInstance().getImageLoader();

//UI
NetworkImageView avatarImageView;
TextView name;
TextView infos;
TextView distance;
RelativeLayout detailView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);

setUpMapIfNeeded();

detailView = (RelativeLayout) findViewById(R.id.detailView);
avatarImageView = (NetworkImageView) findViewById(R.id.imageView);
name = (TextView) findViewById(R.id.name);
infos = (TextView) findViewById(R.id.info);
distance = (TextView) findViewById(R.id.distance);


query.nearUsers(new QueryAPI.ApiResponse<List<ModelUser>>() {
@Override
public void onCompletion(List<ModelUser> result) {

users = result;

setUpClusterer();
}
});

}

@Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}


private void setUpMap() {
mMap.setMyLocationEnabled(true);
}

private void setUpClusterer() {

// Position the map.
getMap().moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(46.155115, 2.473060), 5));

// Initialize the manager with the context and the map.
// (Activity extends context, so we can pass 'this' in the constructor.)
mClusterManager = new ClusterManager<ModelUser>(this, getMap());

// Point the map's listeners at the listeners implemented by the cluster
// manager.
getMap().setOnCameraChangeListener(mClusterManager);
getMap().setOnMarkerClickListener(mClusterManager);
mClusterManager.setRenderer(new PersonRenderer());
mClusterManager.setOnClusterItemClickListener(this);
mClusterManager.setOnClusterItemInfoWindowClickListener(this);

// Add cluster items (markers) to the cluster manager.
addItems();
}

private void addItems() {

for (int i = 0; i < users.size(); i++) {

ModelUser user = users.get(i);

mClusterManager.addItem(user);
}

}

protected GoogleMap getMap() {
setUpMapIfNeeded();
return mMap;
}

@Override
public boolean onClusterItemClick(ModelUser item) {

Log.d("User clicked:", item.getName());
avatarImageView.setImageUrl(item.getAvatar_url(), imageLoader);
name.setText(item.getName());
infos.setText(item.getAge());
double d = Double.parseDouble(item.getDistance());
distance.setText( String.format("%.1f", d) + "Km");
detailView.setVisibility(View.VISIBLE);
return false;
}

@Override
public void onClusterItemInfoWindowClick(ModelUser item) {

Log.d("User Window clicked:", item.getName());
}

/**
* Draws profile photos inside markers (using IconGenerator).
* When there are multiple people in the cluster, draw multiple photos (using MultiDrawable).
*/
private class PersonRenderer extends DefaultClusterRenderer<ModelUser> {
private final IconGenerator mIconGenerator = new IconGenerator(getApplicationContext());
private final UICircularImage mImageView;
//private final int mDimension;

public PersonRenderer() {
super(getApplicationContext(), getMap(), mClusterManager);

View profile = getLayoutInflater().inflate(R.layout.map_marker_item, null);
mIconGenerator.setContentView(profile);
mImageView = (UICircularImage) profile.findViewById(R.id.avatarImageView);

}

@Override
protected void onBeforeClusterItemRendered(ModelUser user, MarkerOptions markerOptions) {
// Draw a single person.
// Set the info window to show their name.
// mImageView.setImageUrl(user.getAvatar_url(), imageLoader);
Picasso.with(getApplicationContext())
.load(user.getAvatar_url())
.noFade()
.into(mImageView, new com.squareup.picasso.Callback() {
@Override
public void onSuccess() {

//reload the marker HERE

}

@Override
public void onError() {

}
});
Bitmap icon = mIconGenerator.makeIcon();
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon)).title(user.getName());
}

}


Any idea why?

EDIT: I realized that sometimes it does load all the images, I think the problem comes from the async task. So my question is now: if I implement a callback to know when Picasso has finished to load the image, how can I reload this specific marker?

Answer

We'll load raw bitmap from Picasso and then pass it to marker representing current user

Picasso.with(getApplicationContext())
        .load(user.getAvatar_url())
        .into(new com.squareup.picasso.Target() {
            @Override
            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                // let's find marker for this user
                Marker markerToChange = null;
                for (Marker marker : mClusterManager.getMarkerCollection().getMarkers()) {
                    if (marker.getPosition().equals(user.getPosition())) {
                        markerToChange = marker;
                        break;
                    }
                }
                // if found - change icon
                if (markerToChange != null) {
                    markerToChange.setIcon(BitmapDescriptorFactory.fromBitmap(bitmap));
                }
            }
            @Override
            public void onBitmapFailed(Drawable errorDrawable) {
            }
            @Override
            public void onPrepareLoad(Drawable placeHolderDrawable) {
            }
        });

I have some troubles with Picasso too. So, i recommend to use Glide

compile 'com.github.bumptech.glide:glide:3.5.2'



Glide.with(getApplicationContext()).
            load(user.getAvatar_url())
            .asBitmap()
            .fitCenter()
            .into(new SimpleTarget<Bitmap>() {
                @Override
                public void onResourceReady(Bitmap bitmap, GlideAnimation<? super Bitmap> glideAnimation) {
                    // let's find marker for this user
                    Marker markerToChange = null;
                    for (Marker marker : mClusterManager.getMarkerCollection().getMarkers()) {
                        if (marker.getPosition().equals(user.getPosition())) {
                            markerToChange = marker;
                            break;
                        }
                    }
                    // if found - change icon
                    if (markerToChange != null) {
                        markerToChange.setIcon(BitmapDescriptorFactory.fromBitmap(bitmap));
                    }
                }
            });
Comments