Add an Image from url into custom InfoWindow google maps v2 Add an Image from url into custom InfoWindow google maps v2 android android

Add an Image from url into custom InfoWindow google maps v2


I've been building a similar app.

First of all, the reason your InfoWindow is not showing the downloaded image is because the MapFragment renders the view into a Canvas, and then draws that. What you're seeing in the info window aren't the views you created, but a "picture" or "screenshot" of them. You basically need to call showInfoWindow() again on the Marker object, and that will re-render the Canvas and your image will now be visible.

However, that being said, in my experience loading the Bitmap from the URL and then setting it isn't the best solution. Android doesn't handle Bitmaps very well. After loading several bitmaps, an OutOfMemoryError exception is just a matter of time, depending on the amount of system memory you have.

I'd recommend using the Picasso library, which handles the asynchronous downloading, and caching (in memory and disk) and makes the actual image loading just one line (Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);). (more info at http://square.github.io/picasso/)

The previous answer was good, except that as he said, that "delay" is a little bit too magical for my taste. Picasso has the option of using callbacks, and I'd recommend using that (I'm using that in my app).

First create a class (it can be internal to your activity) that implements Picasso's Callback interface, and receives a Marker in the constructor (so you can call showInfoWindow() on that marker again.

private class InfoWindowRefresher implements Callback {   private Marker markerToRefresh;   private InfoWindowRefresher(Marker markerToRefresh) {        this.markerToRefresh = markerToRefresh;    }    @Override    public void onSuccess() {        markerToRefresh.showInfoWindow();    }    @Override    public void onError() {}}

The info window looks like this:

mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {    @Override    public View getInfoWindow(Marker marker) {        // inflate view window        // set other views content        // set image view like this:        if (not_first_time_showing_info_window) {            Picasso.with(ActivityClass.this).load(restaurantPictureURL).into(imgInfoWindowPicture);        } else { // if it's the first time, load the image with the callback set            not_first_time_showing_info_window=true;            Picasso.with(ActivityClass.this).load(restaurantPictureURL).into(imgInfoWindowPicture,new InfoWindowRefresher(marker));        }        return v;    }    @Override    public View getInfoContents(Marker marker) {        return null;    }});

The callback is pretty simple, as you can see. However, when using this method you MUST be careful to only use the callback in the first call, and not in subsequent calls (I just put in that not_first_time_showing_info_window to reflect the idea... you'll have to see how to include that in your program logic. If you don't do that, the Picasso callback will call showInfoWindow() and that will re-call the callback, which will recall showInfoWindow()... well, you can see where that recursion's going. :)

The main thing is getting the Picasso load with the callback to only run once, and on the subsequent calls, without the callback.


I solved this problem using black magic (aka setting a delay). I took advantage of Picasso's caching and just called showInfoWindow a few milliseconds after the initial loading had began.

Here is my CustomWindowAdapter.

class CustomWindowAdapter implements InfoWindowAdapter{   LayoutInflater mInflater;   Map<Marker, String> imageStringMapMarker;   Context context;   public CustomWindowAdapter(LayoutInflater i,  Map<Marker, String> imageStringMapMarker2, Context context ){      mInflater = i;      imageStringMapMarker = imageStringMapMarker2;   }   @Override   public View getInfoContents(final Marker marker) {      View v = mInflater.inflate(R.layout.custom_info_window, null);      ImageView ivThumbnail = (ImageView) v.findViewById(R.id.ivThumbnail);      String urlImage = imageStringMapMarker.get(marker).toString();      Picasso.with(context).load(Uri.parse(urlImage)).resize(250,250).into(ivThumbnail);      return v;   }   @Override   public View getInfoWindow(Marker marker) {    // TODO Auto-generated method stub     return null;   }}

And here is the method for calling the info window in my Main Activity where I implement the delay.

myMap.setInfoWindowAdapter(new CustomWindowAdapter(this.getLayoutInflater(),imageStringMapMarker, getApplicationContext()));myMap.setOnMarkerClickListener(new OnMarkerClickListener() {    @Override    public boolean onMarkerClick(final Marker mark) {    mark.showInfoWindow();        final Handler handler = new Handler();        handler.postDelayed(new Runnable() {            @Override            public void run() {                mark.showInfoWindow();            }        }, 200);        return true;    }});


Whatever you return from getInfoContents(), at that moment, is converted into a Bitmap and is used for displaying the results. You are not displaying the image until later, when the download is complete, by which point in time the Bitmap is already created and used.

You will need to download the image before getInfoContents() has been called.