ArrayList over writes all previously stored values android - android

I am trying to calculate distance between a location(source location marker) to the other locations stored in an ArrayList(returned from RoutesData) and storing the locations along the distances in another ArrayList. But as I add a location and its distance from source loacation in that array it overrides all previously stored locations and distances with the newly added location and distance.My code for the particular logic is.
Class RoutesData : returns the LatLngs to measure distance
public class RoutesData {
public ArrayList<LatLng> allRoutesMainStops(){
ArrayList<LatLng> allPoints = new ArrayList<LatLng>(Arrays.asList(
//icPoints
new LatLng(33.582752, 73.044503),new LatLng(33.595504, 73.050912),
//station
new LatLng(33.601097, 73.047798),new LatLng(33.598755, 73.055607),new LatLng(33.599970, 73.063225),new LatLng(33.602757, 73.066996),new LatLng(33.604297, 73.075843),new LatLng(33.608692, 73.082024),
//ali nawaz
new LatLng(33.617330, 73.081743),
//centre hosp
new LatLng(33.630072, 73.071996),new LatLng(33.631454, 73.072416),new LatLng(33.633905, 73.062379),new LatLng(33.641462, 73.063376),new LatLng(33.646714, 73.064095),new LatLng(33.651782, 73.064535),new LatLng(33.661329, 73.063974),new LatLng(33.672490, 73.055906),new LatLng(33.683642, 73.047215),new LatLng(33.689706, 73.030363),new LatLng(33.680982, 73.018654),new LatLng(33.671293, 73.016894),
//gpo 1
new LatLng(33.595215, 73.051496),new LatLng(33.593119, 73.054184),new LatLng(33.585280, 73.066763),new LatLng(33.588925, 73.076172),new LatLng(33.599117, 73.080001),new LatLng(33.607101, 73.083641),new LatLng(33.626583, 73.075027),
//new LatLng(33.630072, 73.071996), //duplicate center
new LatLng(33.631550, 73.072534),new LatLng(33.639063, 73.075742),new LatLng(33.643424, 73.077372),new LatLng(33.650480, 73.080152),new LatLng(33.663188, 73.085446),new LatLng(33.696970, 73.062966),new LatLng(33.699527, 73.073920),new LatLng(33.704257, 73.082993),new LatLng(33.707380, 73.088906),new LatLng(33.717143, 73.082961), new LatLng(33.718617, 73.084589), new LatLng(33.720660, 73.083891), new LatLng(33.727328, 73.073823), new LatLng(33.720397, 73.058392), new LatLng(33.733174, 73.087104)
));
return allPoints;
}
}
Class LocationDistances: binds location with distance.
public class LocationDistances {
LatLng locs;
double distances;
}
getOverAllRoute() method in MainActivity: which compares source Location with all the LatLngs returned from RouteData Class and Store them in a list srcLocDisList . All the trouble I am facing is in the First loop which is calculating distances and then adding distances and location to the srcDistList but when ever a new object is added it overwrites all previous objects with the newly added object.
public void getOverAllRoute(){
//to get main route points to measure distance from
RoutesData rD = new RoutesData();
ArrayList<LatLng> mainRoutePoints = rD.allRoutesMainStops();
//Toast.makeText(this,"Size: "+mainRoutePoints.size(), Toast.LENGTH_LONG).show();
//to store location + distances from source
LocationDistances srcLocDis = new LocationDistances();
ArrayList<LocationDistances> srcLocDisList = new ArrayList();
//showMarkerslongLat();
//create source Location
Location srcLoc = new Location("");
srcLoc.setLatitude(sll.latitude);
srcLoc.setLongitude(sll.longitude);
// to compare distances from source location
Location mainPointsLoc = new Location("");
for(int i =0;i<mainRoutePoints.size();i++){
mainPointsLoc.setLatitude(mainRoutePoints.get(i).latitude);
mainPointsLoc.setLongitude(mainRoutePoints.get(i).longitude);
//store distances and location in arraylist
srcLocDis.locs = mainRoutePoints.get(i);
srcLocDis.distances = srcLoc.distanceTo(mainPointsLoc);
srcLocDisList.add(srcLocDis);
Log.d("Location data: ",srcLocDis.locs.toString());
Log.d("Saved Data: ",srcLocDisList.get(i).toString());
}
//Toast.makeText(this,"items1: "+srcLocDisList.size(), Toast.LENGTH_LONG).show();
LocationDistances min=null;
for(LocationDistances x:srcLocDisList){
String srcLocDisLocFile = x.locs.latitude+" "+x.locs.longitude+" distances:"+x.distances;
min=(min==null||x.distances<min.distances)?x:min;
Log.d("LocDist:",Double.toString(x.distances));
}
LatLng srcStartMin=min.locs;
Toast.makeText(this,srcStartMin.latitude+" "+srcStartMin.longitude+" Distance"+Double.toString(min.distances), Toast.LENGTH_LONG).show();
}

Put LocationDistances srcLocDis = new LocationDistances(); inside the loop otherwise you're always changing the same object.
for(int i =0;i<mainRoutePoints.size();i++){
LocationDistances srcLocDis = new LocationDistances();
....
}

Related

Osmdroid Marker and Json Android

I am working with osmdroid library and android http request. So what I am doing is populating a map with markers where the lat and long are obtained from a database on the server. The question id: How can I call to marker.setOnClickListener out of the method where I do the request.
Here's my code:
RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONArray obj = new JSONArray(response);
for (int i = 0; i < obj.length(); i++) {
JSONObject primer = obj.getJSONObject(i);
double latitud = primer.getDouble(TAG_Latitud);
double longitude = primer.getDouble(TAG_Longitude);
marker = new Marker(map);
marker.setPosition(new GeoPoint(latitud, longitude));
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
mHashMap.put(marker, i);
Terrenos.add(terrenos);
}
marker.setOnMarkerClickListener(new Marker.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker, MapView mapView) {
Intent intent = new Intent(Osmdroid.this, Activity2.class);
startActivity(intent);
return false;
}
});
map.getOverlays().add(marker);
} catch (JSONException e) {
Toast.makeText(Osmdroid.this,"Something Wrong", Toast.LENGTH_LONG).show();
Log.w("exception", e.toString());
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(Osmdroid.this,"Something Wrong",Toast.LENGTH_LONG).show();
Log.w("Error", "No hay respuesta en http");
}
});
queue.add(stringRequest);
}
So, in the code above I create the marker inside the 'for', and I am calling the onClick method when it finished. But when I do this not all the marker works when on click, only the last one created.
Does somebody knows what to do? Please, I really would appreciate your help.
I'll try to explain in details, what are you doing wrong, because it seems that you are missing some basics about OOP programing, variables etc.
What's wrong:
You create multiple objects of type Marker in your loop, but variable named marker stores a reference to only one object of type Marker. You are reusing this variable in you loop end during each iteration you assign another instance of class Marker (another object of type Marker, with its own personal chunk of memory).
Once the loop finishes, your variable still exists and points to one object - and it's the last one Marker instance created, because it was the last value assigned to the variable named marker. You are assigning OnMarkerClickListener to this one and only object.
How to fix it
You want to call method setOnMarkerClickListener (assign OnMarkerClickListener) on every instance of Marker you have created. The way to do it is the same as with the creation: use a loop. You have basically 2 options here:
1) Reuse loop which is already in code and assign listener there. It's the simplest solution, because you can just move the assignment a little bit up in your source code and it would work:
for (int i = 0; i < obj.length(); i++) {
JSONObject primer = obj.getJSONObject(i);
double latitud = primer.getDouble(TAG_Latitud);
double longitude = primer.getDouble(TAG_Longitude);
marker = new Marker(map);
marker.setPosition(new GeoPoint(latitud, longitude));
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
mHashMap.put(marker, i);
Terrenos.add(terrenos);
marker.setOnMarkerClickListener(new Marker.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker, MapView mapView) {
Intent intent = new Intent(Osmdroid.this, Activity2.class);
startActivity(intent);
return false;
}
});
}
map.getOverlays().add(marker);
This is not the most optimal way how to do it though. There is new instance of listener created for each marker, so a little bit of memory is wasted. But you can create an instance of listener before loop, store it in variable and assign the same object to all markers. Try to figure it out as an improvement, once you get things working.
2) You can store markers somewhere and create another loop where you'll assign the listener(s). You can have an variable (or a field in your class) containing list of all markers
List<Marker> markers = new ArrayList<>();
In loop, once a marker is created you can add it to this list:
for (int i = 0; i < obj.length(); i++) {
...
marker = new Marker(map);
marker.setPosition(new GeoPoint(latitud, longitude));
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
markers.add(marker); //addind to the listt
...
Than you can iterate over the list later and assign listener to all of markers. Try to figure the code yourself. There will be similar decision as in previous case: you can create new listener for each marker or reuse one for all of them.
And the last thing: you don't need to craete new variable with list as I mentioned above, because you already have field which contains all your markers. You are using them as keys in a hasmmap:
mHashMap.put(marker, i);
I don't know what is a purpose of this hashmap, but you can get access to all markers (exactly: to an instance of Set with all markers) via mHasnMap.keySet()
Only the last marker has onClick because you set it just to it.
in every looping, the marker object gets a new reference marker = new Marker(map);. Because of that at the last looping, the marker object contains the last references and the onClick method sets just to it.
To solve that you just need to set the onClickand the map.getOverlays().add(marker) inside the loop.
public void onResponse(String response) {
try {
JSONArray obj = new JSONArray(response);
for (int i = 0; i < obj.length(); i++) {
JSONObject primer = obj.getJSONObject(i);
double latitud = primer.getDouble(TAG_Latitud);
double longitude = primer.getDouble(TAG_Longitude);
marker = new Marker(map);
marker.setPosition(new GeoPoint(latitud, longitude));
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
map.getOverlays().add(marker);
mHashMap.put(marker, i);
Terrenos.add(terrenos);
marker.setOnMarkerClickListener(new Marker.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker, MapView mapView) {
Intent intent = new Intent(Osmdroid.this, Activity2.class);
startActivity(intent);
return false;
}
});
}

Plotting coordinates on Route in Gmap (Google Maps Android API)

I'm currently working on one Android application using Google map.
My requirement is to draw a route between source-destination and plot markers at every 500 meters on that route.
I have drawn a route, but not getting how to plot markers at every 500 meters. Is there any Google API available to get coordinates on route, or I have to implement any other logic?
Objectives
The objective is getting a list of LatLng coordinates along the route returned by the Directions API web service at every N meters. Later we can create markers for this list of coordinates.
Solution
The solution has two steps. The first one is getting a list of LatLng that form a route returned by Directions API. You can use a Java Client for Google Maps Services to execute Directions API request and extract a list of LatLng. Have a look at private List<LatLng> getDirectionsPathFromWebService(String origin, String destination) method in my example. This method calls Directions API and loop through legs and steps of the route object to get a complete list of LatLng that form a route.
The second step is implemented in the method private List<LatLng> getMarkersEveryNMeters(List<LatLng> path, double distance). It loops through all LatLng from the first step and creates a list of LatLng at every N meters where N is a distance in meters passed as a second parameter of the method. This method uses internally SphericalUtil class from the Google Maps Android API Utility Library. Have a look at comment to figure out what is happening in this method.
Finally, I create markers from the list that was obtained in second step.
Code snippet
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
private String TAG = "so47784512";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
String origin = "Avinguda Diagonal, 101, 08005 Barcelona, Spain";
String destination = "Carrer de ParĂ­s, 67, 08029 Barcelona, Spain";
LatLng center = new LatLng(41.391942,2.179413);
//Define list to get all latlng for the route
List<LatLng> path = this.getDirectionsPathFromWebService(origin, destination);
//Draw the polyline
if (path.size() > 0) {
PolylineOptions opts = new PolylineOptions().addAll(path).color(Color.BLUE).width(5);
mMap.addPolyline(opts);
}
List<LatLng> markers = this.getMarkersEveryNMeters(path, 500.0);
if (markers.size() > 0) {
for (LatLng m : markers) {
MarkerOptions mopts = new MarkerOptions().position(m);
mMap.addMarker(mopts);
}
}
mMap.getUiSettings().setZoomControlsEnabled(true);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(center, 13));
}
private List<LatLng> getDirectionsPathFromWebService(String origin, String destination) {
List<LatLng> path = new ArrayList();
//Execute Directions API request
GeoApiContext context = new GeoApiContext.Builder()
.apiKey("AIzaSyBrPt88vvoPDDn_imh-RzCXl5Ha2F2LYig")
.build();
DirectionsApiRequest req = DirectionsApi.getDirections(context, origin, destination);
try {
DirectionsResult res = req.await();
//Loop through legs and steps to get encoded polylines of each step
if (res.routes != null && res.routes.length > 0) {
DirectionsRoute route = res.routes[0];
if (route.legs !=null) {
for(int i=0; i<route.legs.length; i++) {
DirectionsLeg leg = route.legs[i];
if (leg.steps != null) {
for (int j=0; j<leg.steps.length;j++){
DirectionsStep step = leg.steps[j];
if (step.steps != null && step.steps.length >0) {
for (int k=0; k<step.steps.length;k++){
DirectionsStep step1 = step.steps[k];
EncodedPolyline points1 = step1.polyline;
if (points1 != null) {
//Decode polyline and add points to list of route coordinates
List<com.google.maps.model.LatLng> coords1 = points1.decodePath();
for (com.google.maps.model.LatLng coord1 : coords1) {
path.add(new LatLng(coord1.lat, coord1.lng));
}
}
}
} else {
EncodedPolyline points = step.polyline;
if (points != null) {
//Decode polyline and add points to list of route coordinates
List<com.google.maps.model.LatLng> coords = points.decodePath();
for (com.google.maps.model.LatLng coord : coords) {
path.add(new LatLng(coord.lat, coord.lng));
}
}
}
}
}
}
}
}
} catch(Exception ex) {
Log.e(TAG, ex.getLocalizedMessage());
}
return path;
}
private List<LatLng> getMarkersEveryNMeters(List<LatLng> path, double distance) {
List<LatLng> res = new ArrayList();
LatLng p0 = path.get(0);
res.add(p0);
if (path.size() > 2) {
//Initialize temp variables for sum distance between points and
//and save the previous point
double tmp = 0;
LatLng prev = p0;
for (LatLng p : path) {
//Sum the distance
tmp += SphericalUtil.computeDistanceBetween(prev, p);
if (tmp < distance) {
//If it is less than certain value continue sum
prev = p;
continue;
} else {
//If distance is greater than certain value lets calculate
//how many meters over desired value we have and find position of point
//that will be at exact distance value
double diff = tmp - distance;
double heading = SphericalUtil.computeHeading(prev, p);
LatLng pp = SphericalUtil.computeOffsetOrigin(p, diff, heading);
//Reset sum set calculated origin as last point and add it to list
tmp = 0;
prev = pp;
res.add(pp);
continue;
}
}
//Add the last point of route
LatLng plast = path.get(path.size()-1);
res.add(plast);
}
return res;
}
}
Conclusion
You can see a result of sample code in the following screenshot
The sample project can be found on GitHub:
https://github.com/xomena-so/so47784512
Do not forget to replace an API key with your's.
I hope this helps!

WeightedLatLng and Collection<WeightedLatLng>

I am using the android API for heatmap. I've imported the dependencies and added the heatmap code at the end of my activity.
List<String> temp = Arrays.asList(coordinates.get(i).split(";"));
LatLng coor = new LatLng(Double.parseDouble(temp.get(1)), Double.parseDouble(temp.get(2)));
// Create a heat map tile provider, passing it the latlngs
WeightedLatLng data = new WeightedLatLng(coor, Double.parseDouble(temp.get(0)) );
mProvider = new HeatmapTileProvider.Builder()
//.weightedData(data) //doesn't work
.data(coor) //doesn't work either
.build();
}
I get the following error in the weightedData line:
WeightedData(java.util.Collection<com.google.maps.android.heatmaps.WeightedLatLng>) in Builder cannot be applies (com.google.maps.android.heatmaps.WeightedLatLng)
I tried adding a cast, but that makes the app crash. I have been googling for a long time and trying all kinds of things. Any ideas?
Builder weightedData and data methods take as a parameter a collection:
weightedData(Collection<WeightedLatLng> val)
Try adding all your data to an ArrayList and then pass it to your builder.
WeightedLatLng data = new WeightedLatLng(coor, Double.parseDouble(temp.get(0)) );
ArrayList<WeightedLatLng> weightedLatLngs = new ArrayList<>();
weightedLatLngs.add(data);
mProvider = new HeatmapTileProvider.Builder().weightedData(weightedLatLngs).build();
Ideally your heatmap should contain many weighted latlngs, so loop through your coordinates and add them all into the arraylist.
Hi i think you should write code like this
List<String> temp = Arrays.asList(coordinates.get(i).split(";"));
LatLng coor = new LatLng(Double.parseDouble(temp.get(1)), Double.parseDouble(temp.get(2)));
// Create a heat map tile provider, passing it the latlngs
WeightedLatLng data = new WeightedLatLng(coor, Double.parseDouble(temp.get(0)) );
mProvider = new HeatmapTileProvider.Builder();
mProvider.weightedData(data);
mProvider.data(coor);
mProvider = mProvider.build();

How to parse json into android to compare users location to nearest 10 locations?

Im getting the server response for store locations and its basically a master array with dictionaries:
[ masterArray :
{name = main,
lat = 15.948
long= 88.853
},
{name = 5th Street,
lat = 15.294
long= 88.743
},
{name = Cannes Blvd,
lat = 15.235
long= 88.765
},
]
I need to loop through each store, get the lat/long, compare it to users location, create a new array with just the top 5 nearest locations.
Ive got this so far:
try {
//Get master array of locations
JSONArray jsonArray = new JSONArray(Arrays.asList(contentAsString));
//Loop through each dictionary in array
for (int i = 0; i < jsonArray.length; i++) {
//Get the lat&long for
JSONObject sys = jsonArray.getJSONObject("master");
name = sys.getString("name");
latitude = sys.getString("lat");
longitude = sys.getString("long");
//Create location object
//Send to Location.distanceTo() method
//Create new array with distance field added to the original values
}
//Sort and get nearest 5 locations
//Create cards for top 5 locations only
//better use Mirror API
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
What Im stuck in is creating the location object and how to hook that up to the distanceTo method which currently is empty:
//Get distances
public float distanceTo (Location dest) {
//Compare distance passed to user location
//return distance float
return 1;
}
Any help will be much appreciated.

Break out multiple coordinates into multiple latlng googlemap v2

I have a huge list in an XML tag like so:
<coor> -123.3858,41.34119,0
-123.3856,41.34109,0
-123.3852,41.34121,0
-123.3848,41.34139,0</coor>
and need it like this:
new LatLng(-123.3858,41.34119),
new LatLng(-123.3856,41.34109),
new LatLng(-123.3852,41.34121),
new LatLng(-123.3848,41.34139),
to work with google maps v2 android.
I've done a string replace on the coordinates and am getting the correct results like so:
String ll = "),new LatLng(";
coor = coor.replaceAll(",0", ll);
replacing the ,0 for the new LatLng(... I am not figuring out how to change the large string of latlng text into latlng locations to put into my polygon:
PolygonOptions perimeteres = new PolygonOptions().add(coor);
Is there way to do this? Or do I need to separate each out and make them individual latlng?
EDIT::::
String[] splitData = coor.split(",0");
for (String eachSplit : splitData) {
if (!eachSplit.endsWith(",0")) {
//Log.e("EACH",eachSplit);
Log.v("e","new LatLon("+eachSplit+");");
}
}
This is getting me a little closer...
You are going completely in the wrong direction, this
String ll = "),new LatLng(";
coor = coor.replaceAll(",0", ll);
is not the same as
new LatLng(-123.3858,41.34119)
the first gives you a string which does nothing for you, the second is an object which is what you need.
Edit
you need to remove the 0 from the coordinates then you do a string split on the , so you have an array of latitudes and longitudes.
then create a List<LatLng> which is what you need to create a polygon of points
and loop through your points
for(int j=0;j<locationAry.length;j++){
if(j%2 == 0){
lon = Float.parseFloat(locationAry[j+1]);
lat = Float.parseFloat(locationAry[j]);
}
}

Categories

Resources