2

My android using the Google map android API,InfoWindow's image not showing on first click, but it works on second click

I customize the infoWindow using

void setMapInfoWindow(){
    mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
        @Override
        public View getInfoWindow(Marker arg0) {
            return null;
        }

        @Override
        public View getInfoContents(Marker arg0) {
            View v = getLayoutInflater().inflate(R.layout.windowlayout, null);
            final ImageView img = (ImageView)v.findViewById(R.id.imageView3);
            //image
            Picasso.with(context).load("http://imgurl").resize(140, 
        }

    });
}

Here is my marker set up process

void setMarkers(){
    ...

    for (int i = 0; i < jsonArray.length(); i++) {
        JSONObject datas=jsonArray.getJSONObject(i);
        MarkerOptions tmp=new MarkerOptions()
                .title("name")
                .alpha(0.6f)
                .position(new LatLng(123,456));//replace LatLng with sample
        marker=mMap.addMarker(tmp);

    }
    ....
    setMapInfoWindow();
}

After I complete the Marker's setting, I call the setMapInfoWindow() function.

It work on my smartphone, but when you click the infoWindow on first time, It would not show the image ; but it showing when second click.

I test for some cases:

  1. replace the web image to local image, the problem still occur.
  2. store all marker into ArrayList, after all process completed, set all markers to showInfoWindow() , then set all markers to hideInfoWindow(). It works, but there are a infoWindow cannot be closed(the final one).
  3. I'm trying use the Bitmap to get the image, But It not showing image, I trying a lot of ways from stackoverflow. But it work when using the Picasso library.

Thanks

the problem solved by: it seems the google web service's image URL will be changed to another URL when loading.

example:

https://maps.googleapis.com/maps/api/place/photo?photoreference=

it will be changed to following URL by google:

https://lh4.googleusercontent.com/......

so I change the boolean not_first_time_showing_info_window to int,and callback three times

    int not_first_time_showing_info_window=0;
    //show image
    try {
        if(not_first_time_showing_info_window==2){
            not_first_time_showing_info_window=0;
            Picasso.with(HomeActivity.this).load("http://....").resize(600,400).into(img);
        }
        else if (not_first_time_showing_info_window==1) {
            not_first_time_showing_info_window++;
            Picasso.with(HomeActivity.this).load("http://....").resize(600, 400).into(img,new InfoWindowRefresher(marker));
        }else if(not_first_time_showing_info_window==0){
            not_first_time_showing_info_window++;
            Picasso.with(HomeActivity.this).load("http://....").resize(600,400).into(img,new InfoWindowRefresher(marker));
        }
    } catch (Exception e) {
        img.setImageDrawable(null);
    }
Steven Chou
  • 1,504
  • 2
  • 21
  • 43

4 Answers4

4

First you can make a custom callback class to implement the com.squareup.picasso.Callback:

 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() {}
    }

Second, declare a boolean variable in your activity:

boolean not_first_time_showing_info_window;

Third, implement the public View getInfoContents(Marker marker) method:

   @Override
   public View getInfoContents(Marker marker) {
      View v = getLayoutInflater().inflate(R.layout.custom_window, null);
      ImageView image = (ImageView)v.findViewById(R.id.image_view);

      if (not_first_time_showing_info_window) {
          Picasso.with(MainActivity.this).load("image_URL.png").into(image);

      } else {
          not_first_time_showing_info_window = true;                         
          Picasso.with(MainActivity.this).load("image_URL.png").into(image, new InfoWindowRefresher(marker));
      }
      return v;
   }

You can also visit this GitHub page for completed implementation.

ztan
  • 6,861
  • 2
  • 24
  • 44
  • When "onSuccess" called, it will cause whole app stop at "showInfoWindow" function (not crash) , and it can't do any thing. I remove the "showInfoWindow" from the "onSuccess" func, it works(but my problem still happened). – Steven Chou May 12 '15 at 18:41
  • 1
    What do u mean by "stop"? Does it show anything in your logcat? Or did u put a breakpoint in the onSuccess method? – ztan May 12 '15 at 18:46
  • 1
    Also, are all your markers placed in a same location? You might try to just put one marker per location, and see if the image shows? – ztan May 12 '15 at 20:57
  • My markers locate at difference location. "Stop" means the whole screen stopped, stop at the infoWindow shown moment, and I can't touch any other markers, whole screen can't be touched until shown system message.. "the app will close(in chinese)". – Steven Chou May 13 '15 at 09:32
  • I find I didn't add the "if" condition, it cause it has a callback loop.But When I add it, the problem still exists, the first click's infoWindow not showing image – Steven Chou May 13 '15 at 12:52
  • I solved this problem by http://stackoverflow.com/a/22009558/2971851 . thank you ! – Steven Chou May 13 '15 at 13:12
  • 1
    That probably not a good way to do it, it will call the `showInfoWindow()` method twice, every time you click a marker. Also, If you marker trying to download a large image, it might take more than 2 seconds to download, so the `postDelayed` will still show no image. – ztan May 13 '15 at 13:24
  • Which "if" condition you missed? If you use the `onSuccess()` method to do it, it should show an image in first click, you can also download this working sample project: https://github.com/jbj88817/GoogleMap-InfoWindow-android – ztan May 13 '15 at 14:50
  • It's work! It seems the "setInfoWindowAdapter" can't put behind marker added – Steven Chou May 14 '15 at 17:24
  • Dear Ztan, It sometimes shown on second click, sometimes work on first click, can you help me? – Steven Chou May 18 '15 at 11:00
  • @A-U, can you post your updated code in the question? or put in a public github? – ztan May 18 '15 at 15:50
  • Dear Ztan, I updated the code in main content. Thanks. – Steven Chou May 18 '15 at 17:11
  • Hi @ztan I know its being a while since this post, I have a question about the "not_first_time_showing_info_window" variable, the thing is in my app I have more than one markers and this solutions works like charm (thanks btw) on the first marker you press, but only on that, when you press another marker the first time it doesnt show the picture (if you Log the not_first_time_showing_info_window variable it is because it's only false the first time no matter what marker are you pressing. Thanks! :) – neteot Aug 11 '15 at 10:25
1

Example that works to me with Kotlin and Glide with data binding:

    class CustomInfoWindow(private val context: Context, 
                   private val markerModels: List<MarkerModel>) : GoogleMap.InfoWindowAdapter {

private var binding = ViewInfoWindowBinding.inflate(LayoutInflater.from(context))
private val images: HashMap<Marker, Bitmap> = HashMap()
private val targets: HashMap<Marker, CustomTarget<Bitmap>> = HashMap()

private fun bind(marker: Marker) {
    val markerModel = markerModels.first { it.name == marker.title }
    val image = images[marker]

    with(binding) {
        tvName.text = markerModel.name
        tvAddress.text = markerModel.address
        
        if (image == null) {
            Glide.with(context)
                .asBitmap()
                .load(markerModel.imageUrl)
                .dontAnimate()
                .into(getTarget(marker))
        } else {
            ivMarker.setImageBitmap(image)
        }
    }
}

override fun getInfoContents(marker: Marker): View {
    bind(marker)
    return binding.root
}

override fun getInfoWindow(marker: Marker): View {
    bind(marker)
    return binding.root
}

inner class InfoTarget(var marker: Marker) : CustomTarget<Bitmap>() {

    override fun onLoadCleared(placeholder: Drawable?) {
        images.remove(marker)
    }

    override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
        images[marker] = resource
        marker.showInfoWindow()
    }
}

private fun getTarget(marker: Marker): CustomTarget<Bitmap> {
    var target = targets[marker]
    if (target == null) {
        target = InfoTarget(marker)
        targets[marker] = target
    }
    return target
}
}

Next set custom info window adapter:

    map.setInfoWindowAdapter(CustomInfoWindow(context, markerModels))

And at marker listener set as next:

  map.setOnMarkerClickListener { marker ->
    if (marker.isInfoWindowShown) {
      marker.hideInfoWindow()
    } else {
      marker.showInfoWindow()
    }
    true
  }
Javi AP
  • 392
  • 3
  • 8
0

I think Google has been listening and here's the solution that works for me. While setting up the cluster,

getMap().setOnMapLoadedCallback(mOnMapLoaded);

And once the map gets loaded, all the markers can be retreived from the clusterManager,

private GoogleMap.OnMapLoadedCallback mOnMapLoaded = () -> {
    LogUtil.i(TAG, "Map has been loaded.");
    showInfoWindow();
};

private boolean showInfoWindow() {
    final WorkHeader selected = mWorkContainer.getSelectedHeader();
    Collection<Marker> markers = mClusterManager.getMarkerCollection().getMarkers();
    for (Marker marker : markers) {
        if (marker.getTitle().contains(selected.siteName)) {
            if (marker.getTitle().contains(selected.siteAddress)) {
                mClusterManager.onMarkerClick(marker);
                return true;
            }
        }
    }
    return false;
}
Novjean
  • 51
  • 1
  • 5
0

i had the same problem using Glide rather than Picasso but i made a simple solution i don't know how efficient it will be but it works fine with me , anyway i would like to share it with you

private Marker lastClicked;
private HashSet<String> markerIdSet=new HashSet<>();

@Override
public boolean onMarkerClick(Marker marker) {
    lastClicked=marker;
    if(!markerIdSet.contains(marker.getId()))
    {
        marker.showInfoWindow();
        marker.hideInfoWindow();
        Handler handler=new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                lastClicked.showInfoWindow();
            }
        },150);
        markerIdSet.add(marker.getId());
        return true;
    }
    else
    {
        marker.showInfoWindow();
        return true;
    }
}

so basically you will creat a HashSet of String (markerID) if the HashSet does not contain that marker id so we add it to the HashSet, and call the marker.showInfoWindow(); to show the infowindow and marker.hideInfoWindow(); to hide it then using Handler object, code execution will wait 150ms and then show the infowindow calling marker.showInfoWindow(); again ,doing that you will get the photo from the first click.

technically you are forcing the code to click the marker twice automatically for the first time of each marker.

please let me know if it worked.

Kenan Jabr
  • 1
  • 1
  • 1