Android add dynamics data to InfoWindow - android

I am working on an application using a Google Map and the Google Places API, let's say I populate the map with different Markers and that I keep track of those Markers inside a
Map<Marker, Place> places = new HashMap<Marker, Place>();
Here is my Place's class :
public class Place {
String placeId;
String name;
public Place(String placeId, String name) {
this.placeId = placeId;
this.name = name;
}
}
I would like to be able to dynamically fill an InfoWindow with data fetched based on the placeId argument, here is what I do inside the InfoWindowAdapter :
map.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
public View getInfoWindow(Marker marker) {
return null;
}
#Override
public View getInfoContents(Marker marker) {
View v = getLayoutInflater().inflate(R.layout.info_window_layout, null);
TextView placeName = (TextView)v.findViewById(R.id.info_window_place_name);
Place place = places.get(marker);
if (place != null) {
placeName.setText(place.name);
String photoUrl = "http://www.plopcontenido.com/wp/wp-content/themes/PlopTheme/img/logo.png";
new DownloadPlacePhoto(v, marker, placeName.toString()).execute(photoUrl);
}
return v;
}
});
private class DownloadPlacePhoto extends AsyncTask<String, Void, Bitmap> {
View v;
Marker marker;
String placeName;
public DownloadPlacePhoto(View v, Marker marker, String placeName) {
this.v = v;
this.marker = marker;
this.placeName = placeName;
}
#Override
protected Bitmap doInBackground(String... urls) {
Bitmap download;
try {
InputStream in = new URL(urls[0]).openStream();
download = BitmapFactory.decodeStream(in);
return download;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Bitmap download) {
if (download != null) {
ImageView placeImage = (ImageView)v.findViewById(R.id.info_window_place_photo);
placeImage.setImageBitmap(download);
placeImage.setContentDescription(this.placeName);
placeImage.setVisibility(View.VISIBLE);
if (this.marker.isInfoWindowShown()) {
this.marker.hideInfoWindow();
this.marker.showInfoWindow();
}
}
}
}
The thing is the InfoWindow is a "snapshot" and not a live representation (and I totally understand why) is that the associated Asynctask will run inside another thread so the snapshot will already be taken without my fetched data.
I heard people talking about Observer Pattern and other talking about "you need to get your data stored before you enter the getInfoWindow function, but due to Google Places limitations I can't afford to perform two more requests (one for the picture, and the other one for more data about a specific place) for each Marker.
Any idea about how I could perform this ?

The gist of this question & answer is to re-show the InfoWindow with marker.showInfoWindow() when you have all the data you need and until then you could show the data you already have or some "loading ..."-text.
When doing so, you have to check if the user unselected the respective marker or selected another marker in the meantime.

Related

infoWindow's image not showing on first click, but it works on second click

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:
replace the web image to local image, the problem still occur.
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).
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);
}
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.
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
}
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;
}
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.

Refresh many Google Map markers position, without refresh the whole map in Android

I'm currently developing an Android app that have to receive GPS positions from other devices every minutes, and display them on a map.
I'm using the GoogleMaps Api V2,
What i'd like to do, is to refresh the position marker very time a new position is received. (I don't want to refresh the whole map)
For the moment, I've added a button in the menu that enables me to refresh the entire map.
To detail to structure, I have a service that run MQTT, and every time a position is received, I add it into an Hashmap, that represents my map data source.
This HashMap is a Singleton that extends Observable.
Moreover, my fragment that display the my implements Observer.
Code from my Fragment that implements Observer
public void update(Observable observable, final Object object)
{
if (observable instanceof ListPositions && object != null)
{
Position p = (Position) object;
LatLng position = new LatLng(p.getLatitude(), p.getLongitude());
// Where i'd like to move the markers
}
else
{
// Where i'd like to remove the marker from the map
}
}
Code From my Singleton List of position
public class ListPositions extends Observable{
private HashMap<String,Position> mapPosition;
private ListPositions()
{
mapPosition = new HashMap<String, Position>();
VehicleMapFragment mapFragmentObserver = new VehicleMapFragment();
this.addObserver(mapFragmentObserver);
}
private static ListPositions INSTANCE = null;
public static synchronized ListPositions getInstance()
{
if (INSTANCE == null)
{ INSTANCE = new ListPositions();
}
return INSTANCE;
}
public int getNumberOfPosition()
{
return mapPosition.size();
}
public void addPosition(String key, Position p){
mapPosition.put(key,p);
setChanged();
notifyObservers(p);
}
public void removePosition(String key){
mapPosition.remove(key);
setChanged();
notifyObservers();
}
Code From myService that runs MQTT
public void onPositionMessageReceived(MqttMessage message, String source)
{
Gson gson = new Gson();
String s = gson.toJson(message.toString());
String jsonPosition = gson.toJson(message.toString());
jsonPosition = formatMessage(jsonPosition);
Position p = gson.fromJson(jsonPosition, Position.class);
ListPositions.getInstance().addPosition(source, p);
}
Can someone know how to move each markers individually without refreshing the whole map, in my update function from my Observer Fragment?
May I use a Handler to update the Map, from an other thread to modify the Main UI Thread ?
Many thanks
EDIT :
Because the first methode given by AniV didn't work for me, I've tried with an Asyntask that runs when my Observer get a notification from the Observable List.
Code from the Observer Fragment :
public void update(Observable observable, final Object object)
{
if (observable instanceof ListPositions && object != null)
{
Position p = (Position) object;
position = new LatLng(p.getLatitude(), p.getLongitude());
options = new MarkerOptions().position(position).title("TEST").snippet("TEST");
PositionUpdate positionUpdaterTask = new PositionUpdate(myGoogleMap, options, position);
positionUpdaterTask.execute();
}
}
Code from the AsyncTask :
public class PositionUpdate extends AsyncTask<Void, Void, Void>{
private GoogleMap myGoogleMap;
private MarkerOptions options;
private LatLng positionToAdd;
public PositionUpdate(GoogleMap googleMap, MarkerOptions options, LatLng position)
{
this.myGoogleMap = googleMap;
this.options = options;
this.positionToAdd = position;
}
#Override
protected Void doInBackground(Void...voids)
{
return null;
}
#Override
protected void onPostExecute(Void aVoid)
{
if (myGoogleMap != null)
{
myGoogleMap.addMarker(options.position(positionToAdd));
Log.i(ConstElisa.LOG_ELISA, "MARKER ADDED");
}
else
{
Log.e(ConstElisa.LOG_ELISA, "ERROR ADDING THE MARKER");
}
super.onPostExecute(aVoid);
}
However, in this case, myGoogleMap variable is always null, so the marker is never added to the Google Map.
Does someone have an idea why this variable is null ?
I finally succeeded in doing that thing by using the AsyncTask.
In my EDIT, I said that I had some trouble with the null instance of my Google Maps object.
This was caused by my Singleton Observable. Indeed, in the constructor, I used
VehicleMapFragment mapFragmentObserver = new VehicleMapFragment();
this.addObserver(mapFragmentObserver);
This code sample recreated another instance of my Fragment, and that the reason why ii had Null objects.
To correct this problem, I simply used :
ListPositions.getInstance().addObserver(this);
in my Fragment Observer.
So if you want to update a marker position without refreshing the whole map,
you can use the Observer/Observable Pattern, and use an Asynctask to update the marker position.
You have two options here:
Either update the marker position programatically using setPosition() method.
Marker marker = googleMap.addMarker(new MarkerOptions().position(entry.getValue()).title(entry.getKey()));
Use this object to change its position:
marker.setPosition(new LatLng(5, 5));
OR as you said, Make use of Handlers:
Handler locationHandler;
final static long REFRESH = 10 * 1000;
final static int SUBJECT = 0;
private GoogleMap mMap;
private Marker myMarker = null;
and onCreate()
locationHandler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == SUBJECT) {
updateMarker();
this.sendEmptyMessageDelayed(SUBJECT, REFRESH);
}
}
};
Handler option is better in cases where you have to update the position at a specific time interval.
I have something like this. I receive a list of devices every 5 minutes to update locations of the map.
What do you think about this
private HashMap<String, Marker> mMarkers = new HashMap<>();
private void drawDevicesOnMap() {
if (isMapReady) {
for (Device device : mDeviceList) {
List<com.model.Location> locationList = device.getLocations();
if (locationList != null && !locationList.isEmpty()) {
if (mMarkers.containsKey(device.getId())) { //update
Marker m = mMarkers.get(device.getId());
m.setPosition(device.getLocations().get(0).getCoordinates().getLatLng());
mMarkers.put(device.getId(), m);
} else { //add
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(locationList.get(0).getCoordinates().getLatLng());
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(device.getHue()));
markerOptions.title(device.getNickname());
Marker marker = mMap.addMarker(markerOptions);
mMarkers.put(device.getId(), marker);
}
}
}
}
}
if the marker for a device with x id is found in the HashMap, you update its location.

Map clustering - max zoom markers still clustered

I'm using android maps utils for clustering the markers on google maps api v2. It worked fine, but when I added 2000+ markers, on max zoom it is still clustered (markers still have numbers):
Here is my method for filling map with markers:
public void getRiverData(String state, String type) {
URL = getResources().getString(R.string.base_url) + state + "/" + type
+ getResources().getString(R.string.end_url);
SimpleXmlRequest<XMLData> simpleRequest = new SimpleXmlRequest<XMLData>(
URL, XMLData.class, new Response.Listener<XMLData>() {
#Override
public void onResponse(XMLData response) {
// Initialize the manager with the context and the map.
// (Activity extends context, so we can pass 'this' in
// the constructor.)
mClusterManager = new ClusterManager<MarkerItem>(
getActivity(), map);
mClusterManager.setRenderer(new ClusterRenderer(
getActivity(), map, mClusterManager));
// response Object
waterItemsList = response.getNews();
for (News item : waterItemsList) {
if (item.getRiver_name() != null
&& item.getRiver_name() != "") {
water_level_value = item.getWater_level_value();
if (water_level_value != null
&& !water_level_value.equals(0)
&& !water_level_value.equals("")) {
MarkerItem offsetItem = new MarkerItem(item);
mClusterManager.addItem(offsetItem);
}
map.setOnMarkerClickListener(mClusterManager);
map.setInfoWindowAdapter(new InfoWindowAdapter() {
#Override
public View getInfoWindow(Marker marker) {
return null;
}
#Override
public View getInfoContents(Marker marker) {
try {
View v = getActivity()
.getLayoutInflater()
.inflate(
R.layout.marker_info,
null);
TextView title = (TextView) v
.findViewById(R.id.tvMarkerTitle);
TextView info = (TextView) v
.findViewById(R.id.tvMarkerInfo);
title.setText(marker.getTitle()
.toString());
info.setText(marker.getSnippet()
.toString());
return v;
} catch (Exception e) {
// kliknięcie w cluster
return null;
}
}
});
}
}
map.setOnCameraChangeListener(mClusterManager);
map.setOnInfoWindowClickListener(mClusterManager);
mClusterManager.cluster();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// error Object
error.printStackTrace();
}
});
AppController.getInstance().addToRequestQueue(simpleRequest);
}
Can anyone help me? Why is it not working?
You can extend DefaultClusterRenderer class and set minimum markers to cluster.
public class InfoMarkerRenderer extends DefaultClusterRenderer<MyCustomMarker> {
public InfoMarkerRenderer(Context context, GoogleMap map, ClusterManager<MyCustomMarker> clusterManager) {
super(context, map, clusterManager);
//constructor
}
#Override
protected void onBeforeClusterItemRendered(final MyCustomMarker infomarker, MarkerOptions markerOptions) {
// you can change marker options
}
#Override
protected boolean shouldRenderAsCluster(Cluster cluster) {
return cluster.getSize() > 5; // if markers <=5 then not clustering
}
}
Via trail and error I found that if the markers are within ~10 feet (equivalent to 0.0000350º difference in lat or long), the markers don't decluster even at the max zoom level.
One way to solve for this problem is to implement a custom Renderer and let the app decide when to cluster. For example, the below code will cluster only when there are more than 1 marker and not at max Zoom. In other words it will decluster all markers at max zoom.
mClusterManager.setRenderer(new DefaultClusterRenderer<MyItem>(mContext, googleMap, mClusterManager) {
#Override
protected boolean shouldRenderAsCluster(Cluster cluster) {
if(cluster.getSize() > 1 && mCurrentZoom < mMaxZoom) {
return true;
} else {
return false;
}
}
});
To filter markers that have the same position, you could simply use a hashmasp, whose key is computed from the marker coordinates.
Something like:
Map<String, Marker> uniqueMarkers = new HashMap<String, Marker>();
for (Markers m : allMarkers) {
// Compute a key to filter duplicates
// You may need to account for small floating point precision errors by
// rounding those coordinates
String key = m.getLatitude() + "|" + m.getLongitude();
if (uniqueMarkers.get(key)!=null ) {
// Skip if we have a marker with the same coordinates
continue;
}
// Add marker and do something with it
uniqueMarkers.add(key, m);
// ...
}

Refreshing makers (ClusterItems) in Google Maps v2 for Android

I'm using Google Maps Android API Utility Library and I'm downloading certain images from internet that I want to use as markers.
The way I'm doing it is like in the following snippet:
class MarkerItemClusterRenderer extends DefaultClusterRenderer<MarkerItem> {
...
#Override
protected void onBeforeClusterItemRendered(MarkerItem item,
final MarkerOptions markerOptions) {
super.onBeforeClusterItemRendered(item, markerOptions);
mImageLoader.get(item.getImageUrl(), new ImageListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.i("XXX", error.toString());
}
#Override
public void onResponse(ImageContainer response, boolean isImmediate) {
if (response != null && response.getBitmap() != null) {
mImageIcon.setImageBitmap(response.getBitmap());
Bitmap icon = mIconGenerator.makeIcon();
Bitmap bhalfsize = Bitmap.createScaledBitmap(icon, 150,
150, false);
markerOptions.icon(BitmapDescriptorFactory
.fromBitmap(bhalfsize));
}
}
});
}
The problem is, that when the image is downloaded, the map (and thus the marker) doesn't refresh, so most of the times (but not always) I still see the red default markers.
I tried to do mImageIcon.invalidate(); mImageIcon.requestLayout(); but there's still no luck.
Is there anyway to achieve this?
Thanks a lot in advance.
You just need to make all this stuff in
protected void onClusterItemRendered(T clusterItem, Marker marker) {
...
}
In onBeforeClusterItemRendered you set icon on MarkerOptions in async callback. At this time it could be added to map and become real Marker. So you icon will be set to already useless object.
That's why you need to do it in onClusterItemRendered
Let's say you have GoogleMap object declared as:
private GoogleMap mMap;
In onResponse() method before applying any change to marker, try writing following statement to clear previous markers:
mMap.clear();
Now set your new marker.
I might be a bit late but i write it down so it can be useful for somebody looking for a solution like i was.
Basically what you have to do is refresh the marker and not the ClusterItem, but i used my own ClusterItem implementation to store some important data.
So your code inside onBeforeClusterItemRendered becomes like this:
LatLngBounds bounds = map.getProjection().getVisibleRegion().latLngBounds; //take visible region on map
if(bounds.contains(item.getPosition()) && !item.hasImage()) { //if item is not inside that region or it has an image already don't load his image
mImageLoader.get(item.getImageUrl(), new ImageListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.i("XXX", error.toString());
}
#Override
public void onResponse(ImageContainer response, boolean isImmediate) {
if (response != null && response.getBitmap() != null) {
mImageIcon.setImageBitmap(response.getBitmap());
Bitmap icon = mIconGenerator.makeIcon();
Bitmap bhalfsize = Bitmap.createScaledBitmap(icon, 150,
150, false);
//Set has image flag
item.setHasImage(true);
//Find the right marker
MarkerManager.Collection markerCollection = mClusterManager.getMarkerCollection();
Collection<Marker> markers = markerCollection.getMarkers();
for (Marker m : markers) {
if (id.equals(m.getTitle())) {
//set the icon
m.setIcon(BitmapDescriptorFactory.fromBitmap(image));
break;
}
}
}
}
});
}
And your MyItem class must have some parameters which are useful for remember our stuff:
public class MyItem implements ClusterItem {
private String itemId;
private LatLng mPosition;
private WMWall wall;
private boolean hasImage = false;
public MyItem(double latitude, double longitude) {
mPosition = new LatLng(latitude, longitude);
}
#Override
public LatLng getPosition() {
return mPosition;
}
public WMWall getWall() {
return wall;
}
public void setWall(WMWall wall) {
this.wall = wall;
}
public String getItemId() {
return itemId;
}
public void setItemId(String itemId) {
this.itemId = itemId;
}
public boolean hasImage() {
return hasImage;
}
public void setHasImage(boolean hasImage) {
this.hasImage = hasImage;
}
}
It is really important to load only the images of markers contained into bounds, otherwise you'll run into OOM.
And if the hasImage() method returns true we don't need to load the image again since it is already stored into the marker object.

Android how to pass class object in snippet in google map v2?

I am working on Android Google Map and I am using MapApiV2. I am able to show the map, user location, markers on the map. My problem is that I want to open an InfoWindow when user click on any marker on the map. I am able to open the window also but I need to show more data in the info video so I am trying to pass the my CustomClass object in the .snippet() methos but it except only string object. So I convert my class object to string by simply doing this (uv.tostring) and pass to snippet() method. Now on the other side when I trying to get the dat from snippet using marker.getSnippt(); I can not access my data from the string. So please suggest me how can I pass my custom class object to snippt so I can acces my get, set methods of custom class.
Below is my code
My Custom class is:
public class UserVerifyer implements UserVerfierInterface{
// <userPojo>
// <frequency>0.0</frequency>
// <message/>
// <status>NOTOK</status>
// <token>ey0dok0vozrhwhe98rt6ydbs</token>
// <url/>
// </userPojo>
private String frequency = "", message = "", status = "", token = "",
url = "";
public static String statusOk = "OK";
public void setFrequency(String freq) {
this.frequency = freq;
}
public String getFrequency() {
return frequency.trim();
}
public void setMessage(String message) {
this.message = message;
}
public String getMessage() {
return message.trim();
}
public void setStatus(String status) {
this.status = status;
}
public String getStatus() {
return status.trim();
}
public void setToken(String token) {
this.token = token;
}
public String getToken() {
return token.trim();
}
public void setUrl(String url) {
this.url = url;
}
public String getUrl() {
return url.trim();
}
}
MyCustomInfo window class is:
public class CustomMarkers implements InfoWindowAdapter {
// private Context context;
// private String text;
// private Integer image;
private final View mWindow;
private final View mContents;
public CustomMarkers(Activity activity) {
// this.context = ctx;
// this.text = text;
// this.image = image;
LayoutInflater inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mWindow = inflater.inflate(R.layout.balloon, null);
mContents = inflater.inflate(R.layout.balloon, null);
}
#Override
public View getInfoContents(Marker marker) {
// TODO Auto-generated method stub
render(marker, mWindow);
return mWindow;
}
#Override
public View getInfoWindow(Marker marker) {
// TODO Auto-generated method stub
render(marker, mContents);
return mContents;
}
private void render(Marker marker, View view) {
String title = marker.getTitle();
TextView titleUi = ((TextView) view.findViewById(R.id.txtTitle));
if (title != null) {
titleUi.setText(title);
} else {
titleUi.setText("");
}
String snippet = marker.getSnippet();
UserVerifyer uv = UserVerifyer.class.cast(snippet);
System.out.println("Sttaus in Marker= "+uv.getStatus());
// uv.getStatus();
TextView snippetUi = ((TextView) view.findViewById(R.id.txtPlace));
if (snippet != null) {
snippetUi.setText(snippet);
} else {
snippetUi.setText("");
}
}
}
and I am adding data in marker like this:
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(new LatLng(getMyLocation().getLatitude(),
getMyLocation().getLongitude())).zoom(17).bearing(90)
.tilt(30).build();
mMap.animateCamera(CameraUpdateFactory
.newCameraPosition(cameraPosition));
UserVerifyer uv = new UserVerifyer();
mMap.addMarker(new MarkerOptions()
.position(
new LatLng(getMyLocation().getLatitude(),
getMyLocation().getLongitude()))
.title("Me")
.snippet(uv.toString())
.icon(BitmapDescriptorFactory.fromResource(R.drawable.user_loc)));
mMap.setInfoWindowAdapter(new CustomMarkers(RecomendationScreen.this));
Please suggest me how can I do this.
Thanks.
Solution:
Instead of converting to string and dive into complexity,I would like to suggest you alternative approach to achieve the desired result in very efficient manner.
You can create a HashMap<Marker, UserVerifyer> ,and you can retrieve object of UserVerifyer by using Marker as the key.so you can easily put the data and retrieve the data from HashMap.
Reference:
Have a look at this example.It is performing exactly what I mean to say.
I hope it will be helpful !!
MehulJoisar's suggestion of using Map<Marker, YourModel> is the usual way to work around the limitation of Android API v2, but there is also another way.
You may use Android Maps Extensions for your task. It adds setData and getData functions to Marker class, so your code would look like this:
UserVerifyer uv = new UserVerifyer();
Marker marker = mMap.addMarker(new MarkerOptions()
.position(
new LatLng(getMyLocation().getLatitude(),
getMyLocation().getLongitude()))
.title("Me")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.user_loc)));
marker.setData(uv);
and later in GoogleMap callback:
//String snippet = marker.getSnippet();
UserVerifyer uv = (UserVerifyer) marker.getData();
System.out.println("Sttaus in Marker= "+uv.getStatus());

Categories

Resources