Adding markers from url with Picasso

2019-04-22 23:01发布

问题:

I'm adding markers to my map from a url using the Picasso library

As a marker isn't an ImageView I tried to use a Target instead

for(int x =0; x < mapIcon_url.length; x++){

    Picasso.with(getActivity()).load(mapIcon_url[x]).resize(marker_size, marker_size+15).into(new Target() {

        @Override
        public void onSuccess(Bitmap b) {
            bitmapMarker = BitmapDescriptorFactory.fromBitmap(b);


            //create marker option
            if(b != null)
                markerOptions = new MarkerOptions().position(marker_position).icon(bitmapMarker));
            else
                markerOptions = new MarkerOptions().position(marker_position).icon(BitmapDescriptorFactory.fromResource(R.drawable.placeholder_pin)).snippet(String.valueOf(x));

            marker = map.addMarker(markerOptions);                              
        }

        @Override
        public void onError() {

            //create marker option                                  
            markerOptions = new MarkerOptions().position(marker_position).icon(BitmapDescriptorFactory.fromResource(R.drawable.placeholder_pin)).snippet(String.valueOf(x));
            marker = map.addMarker(markerOptions);

        }
    }); 
}   

I'm doing this in a loop to add about 20 markers but I find that on first run of the code only 5 or 7 markers are added so I've switched to using the lib and an AsyncTask like this.

for(int x =0; x < mapIcon_url.length; x++){

    new AddMarker().execute(mapIcon_url[x]);
}


public class AddMarker extends AsyncTask<String, Integer, BitmapDescriptor> {

    BitmapDescriptor bitmapMarker1;
    VenueDetails myVenue;

    @Override
    protected BitmapDescriptor doInBackground(String... url) {  
        myUrl = url[0];
        try {
            bitmapMarker1 = BitmapDescriptorFactory.fromBitmap(Picasso.with(getActivity()).load(myUrl).resize(marker_size, marker_size+15).get());
        } catch (IOException e) {
            e.printStackTrace();
        }

        return bitmapMarker1;
    }

    protected void onPostExecute(BitmapDescriptor icon) {

        try {

            map.addMarker(new MarkerOptions().position(marker_position).icon(icon)));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}   

However I'm a bit worried this method could give me some issues when I have alot of markers say about 100. My question would be is this the best way to do this and if not what other options can I try.

回答1:

You have to keep a reference for each Target, otherwise the system automatically releases them when the garbage collector is invoked.

So, the better solution is add each Target to a HashSet and then in onBitmapLoaded() and onBitmapFailed methods from Target, remove the Target itself from the set.

Thank you for the suggestion, now my code work perfectly. Below the pieces of code that implement your suggestion.

[...]//Global var
  private Set<PoiTarget> poiTargets = new HashSet<PoiTarget>();
[...]    
 private void somewhere(){
    PoiTarget pt;
    for(Item item: data) {
        m = map.addMarker(new MarkerOptions()
               .position(new LatLng(item.latitude, item.longitude))
               .title(item.title));
        pt = new PoiTarget(m);
        poiTargets.add(pt);
        Picasso.with(context)
           .load(mapImageURLString)
           .into(pt);
    }
}
[...]
//--------------------------------------------------------
// Inner class
//--------------------------------------------------------
    class PoiTarget implements Target{
        private Marker m;

        public PoiTarget(Marker m) { this.m = m; }

        @Override public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
            m.setIcon(BitmapDescriptorFactory.fromBitmap(bitmap));
            poiTargets.remove(this);
            Tools.msg(" @+ Set bitmap for "+m.getTitle()+" PT size: #"+poiTargets.size());
        }

        @Override public void onBitmapFailed(Drawable errorDrawable) {
            Tools.msg(" @+ [ERROR] Don't set bitmap for "+m.getTitle());
            poiTargets.remove(this);
        }

        @Override public void onPrepareLoad(Drawable placeHolderDrawable) {

        }
    }


回答2:

You have to keep a reference for each Target, otherwise the system automatically releases them when the garbage collector is invoked.

So, the better solution is add each Target to a HashSet and then in onBitmapLoaded() and onBitmapFailed methods from Target, remove the Target itself from the set.