将来自 url 的图像添加到自定义 InfoWindow google maps v2
Posted
技术标签:
【中文标题】将来自 url 的图像添加到自定义 InfoWindow google maps v2【英文标题】:Add an Image from url into custom InfoWindow google maps v2 【发布时间】:2013-09-27 02:32:42 【问题描述】:我正在使用一个 android 应用程序。用户在谷歌地图上搜索餐馆。在谷歌地图上显示他所有邻居餐厅的标记。如果他点击一个标记,它会显示一个自定义信息窗口。我的问题是我无法加载从 Google 地方返回的图像。我得到了正确的图像网址,但我无法在窗口中显示它。
信息窗口
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:orientation="vertical"
android:background="@color/bg_color" >
<ImageView
android:id="@+id/place_icon"
android:layout_
android:layout_
android:focusable="false"" />
<TextView
android:id="@+id/place_title"
android:layout_
android:layout_ />
<TextView
android:id="@+id/place_vicinity"
android:layout_
android:layout_ />
<LinearLayout
android:layout_
android:layout_
android:orientation="horizontal"
android:background="@color/bg_color" >
<RatingBar
android:id="@+id/place_rating"
style="?android:attr/ratingBarStyleSmall"
android:numStars="5"
android:rating="0"
android:isIndicator="false"
android:layout_
android:layout_
android:layout_marginLeft="5dip" />
<ImageView
android:id="@+id/navigate_icon"
android:layout_
android:layout_
android:focusable="false"
android:src="@drawable/navigate" />
</LinearLayout>
在创建时我有这个
mGoogleMap.setInfoWindowAdapter(new InfoWindowAdapter()
// Use default InfoWindow frame
@Override
public View getInfoWindow(Marker arg0)
return null;
// Defines the contents of the InfoWindow
@Override
public View getInfoContents(Marker arg0)
// Getting view from the layout file info_window_layout
View v = getLayoutInflater().inflate(R.layout.info_window_layout, null);
// Getting the snippet from the marker
String snippet = arg0.getSnippet();
// Getting the snippet from the marker
String titlestr = arg0.getTitle();
String cutchar1= "%#";
String cutchar2= "%##";
String ratingstr = snippet.substring(0,snippet.indexOf( cutchar1 ));
String vicinitystr = snippet.substring(snippet.indexOf( cutchar1 )+2, snippet.indexOf( cutchar2 ) );
String iconurl= snippet.substring(snippet.indexOf( cutchar2 )+3);
// Getting reference to the TextView to set latitude
TextView title = (TextView) v.findViewById(R.id.place_title);
TextView vicinity = (TextView) v.findViewById(R.id.place_vicinity);
ImageView image = (ImageView) v.findViewById(R.id.navigate_icon);
// Setting the latitude
title.setText(titlestr);
// declare RatingBar object
RatingBar rating=(RatingBar) v.findViewById(R.id.place_rating);// create RatingBar object
if( !(ratingstr.equals("null")) )
rating.setRating(Float.parseFloat(ratingstr));
vicinity.setText(vicinitystr);
final DownloadImageTask download = new DownloadImageTask((ImageView) v.findViewById(R.id.place_icon) ,arg0);
download.execute(iconurl);
// Returning the view containing InfoWindow contents
return v;
);
DownloadImage 代码是:
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap>
ImageView bmImage;
Marker marker;
boolean refresh;
public DownloadImageTask(final ImageView bmImage, final Marker marker)
this.bmImage = bmImage;
this.marker=marker;
this.refresh=false;
public void SetRefresh(boolean refresh )
this.refresh=true;
/* @Override
protected void onPreExecute()
super.onPreExecute();
bmImage.setImageBitmap(null);
*/
@Override
protected Bitmap doInBackground(String... urls)
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
catch (Exception e)
Log.e("Error", e.getMessage());
e.printStackTrace();
return mIcon11;
@Override
protected void onPostExecute(Bitmap result)
if(!refresh)
SetRefresh(refresh);
bmImage.setImageBitmap(result);
marker.showInfoWindow();
最后,当我执行代码并点击标记时,getInfoContents 不会停止执行并且图标不会出现。
为什么会这样?
【问题讨论】:
Dynamic contents in Maps V2 InfoWindow 的可能重复项 @Mixalis 你有解决方案吗?请分享给我。 【参考方案1】:我一直在构建一个类似的应用程序。
首先,您的 InfoWindow 未显示下载图像的原因是 MapFragment
将视图呈现为 Canvas
,然后将其绘制。您在信息窗口中看到的不是您创建的视图,而是它们的“图片”或“屏幕截图”。您基本上需要在Marker
对象上再次调用showInfoWindow()
,这将重新渲染Canvas
,您的图像现在将可见。
但是,话虽如此,根据我的经验,从 URL 加载 Bitmap
然后设置它并不是最好的解决方案。 Android 不能很好地处理Bitmap
s。加载多个位图后,OutOfMemoryError
异常只是时间问题,具体取决于您拥有的系统内存量。
我建议使用 Picasso 库,它处理异步下载和缓存(在内存和磁盘中)并使实际图像加载只需一行 (Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
)。 (更多信息http://square.github.io/picasso/)
前面的答案很好,只是正如他所说,“延迟”对我的口味来说有点太神奇了。 Picasso 可以选择使用回调,我建议使用它(我在我的应用程序中使用它)。
首先创建一个实现 Picasso 的Callback
接口的类(它可以在您的活动内部),并在构造函数中接收Marker
(这样您就可以再次在该标记上调用showInfoWindow()
。
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()
信息窗口如下所示:
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;
);
如您所见,回调非常简单。但是,在使用此方法时,您必须小心仅在第一次调用中使用回调,而不是在后续调用中(我只是输入 not_first_time_showing_info_window
以反映这个想法......你'我必须看看如何将它包含在你的程序逻辑中。如果你不这样做,Picasso 回调将调用showInfoWindow()
,这将重新调用回调,这将调用showInfoWindow()
...好吧,你可以看到递归的去向。:)
主要是通过回调让 Picasso 加载只运行一次,并且在随后的调用中,没有回调。
【讨论】:
同样的方法,这里的实现更简洁:***.com/a/28885430/431432【参考方案2】:我使用黑魔法(也就是设置延迟)解决了这个问题。我利用了 Picasso 的缓存,并在初始加载开始几毫秒后调用了 showInfoWindow。
这是我的 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;
这是在我实现延迟的主活动中调用信息窗口的方法。
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;
);
【讨论】:
很久没发你的帖子了,你还记得你为什么要调用“mark.showInfoWindow();”吗?在“onMarkerClick”中两次? 嗨,Ignacio,我目前正在重新编写使用此代码的应用程序。我的情况是我需要先下载图片才能将其展示给用户。我想让用户感觉到有什么东西要来了,所以第一个窗口警报是显示占位符窗口,这样用户就可以期待一些东西在片刻之后出现。处理程序将在加载照片的特定实例所需的平均时间之后显示照片。我承认这实际上是一种非常糟糕的方法。但是,我需要在这个项目上快速行动。我现在正在偿还我的技术债务。 很棒的帖子。像魅力一样工作!你拯救了我的一天【参考方案3】:无论您从getInfoContents()
返回什么,此时都将转换为Bitmap
并用于显示结果。直到下载完成后,您才会显示图像,此时 Bitmap
已经创建并使用。
您需要在调用getInfoContents()
之前下载图像。
【讨论】:
其实我想在下载完成后刷新Infowindow。像这样。code.google.com/p/gmaps-api-issues/issues/detail?id=4645 为此,我使用 var refrese 。我怎么能等待 unitll 完成下载?我认为使用 AsyncTask 下载是并行的。 @Mixalis:当您的代码将尝试刷新信息窗口时,您只需转身再次开始另一个下载任务。您填充ImageView
为时已晚(Bitmap
已创建),当您刷新信息窗口时,您将在填充另一个布局实例时创建另一个不同的 ImageView
。您需要缓存Bitmap
,在您的信息窗口再次出现时使用它,而不是开始另一个任务。处理这个问题的一种方法是使用缓存图像加载库——Picasso 可能会起作用。
@Mixalis:但感谢您指出这个问题,因为那里描述的技术很有帮助。我明天会看到为此编写一个示例应用程序,假设我能想到一个很好的相关图像来源...... :-)
泰。我正在等待它......如果发布示例,发布链接会很好
@Mixalis:给你:github.com/commonsguy/cw-omnibus/tree/master/MapsV2/ImagePopups【参考方案4】:
我这样做,也参考@Daniel Gray answer:
if (userImg.getDrawable() == null)
Picasso.with(ctx).load(UtilitiesApp.urlServer + user.getImgUrl())
.error(R.drawable.logo)
.into(userImg, new InfoWindowRefresher(marker));
else
Picasso.with(ctx).load(UtilitiesApp.urlServer + user.getImgUrl())
.error(R.drawable.logo)
.into(userImg);
public class InfoWindowRefresher implements Callback
private Marker markerToRefresh;
public InfoWindowRefresher(Marker markerToRefresh)
this.markerToRefresh = markerToRefresh;
@Override
public void onSuccess()
markerToRefresh.showInfoWindow();
@Override
public void onError()
【讨论】:
以上是关于将来自 url 的图像添加到自定义 InfoWindow google maps v2的主要内容,如果未能解决你的问题,请参考以下文章
IOS:将图像添加到自定义 MKAnnotationview
如何将 FBSDKLoginButton 默认图像添加到自定义 UIButton?
如何在swift ios中将多个图像添加到自定义表格视图单元格?