Solution 1 :
You could use a simple distance formula to archive this:
private Double distance(Double lat1, Double lon1, Double lat2, Double lon2) {
return Math.sqrt (Math.pow((lat1 - lat2), 2) - Math.pow((lon1 - lon2), 2));
}
// The user Location
currentLat = xxxx;
currentLon = xxxx;
if ((markerCoords != null) && (markerCoords.size() > 0)) {
LatLng near = markerCoords.get(0);
for (int x = 1; x < markerCoords.size(); x++) {
Double lat = markerCoords.get(x).latitude;
Double lon = markerCoords.get(x).longitude;
Double currentMarkerdistance = distance(
currentLat,
currentLon,
markerCoords.get(x).latitude,
markerCoords.get(x).longitude);
Double nearMarkerdistance = distance(
currentLat,
currentLon,
near.latitude,
near.longitude);
if (currentMarkerdistance < nearMarkerdistance) {
near = markerCoords.get(x);
}
}
}
// After this process the near variable will hold the near marker
Problem :
I’m quite new to android development and I was wondering if it is possible for me to locate the nearest marker to a user and knowing which marker is closest direct the user there using a polyline and google directions api. The locations of the markers are taken from a database that I have parsed into a list array which I then use to place the markers on the map. I have tried to find help from other questions however they do not seem to fit in my project.
If it is possible for me to find the nearest marker to the user how can I do it if not is there an alternative method I could use??
This is my code for my main activity:
package com.example.defiblocator;
import android.Manifest;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback,
LocationListener,GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener{
public static TextView data;
public static String location;
GoogleMap mapAPI;
SupportMapFragment mapFragment;
Location mLastLocation;
Marker mCurrLocationMarker;
GoogleApiClient mGoogleApiClient;
LocationRequest mLocationRequest;
String delimiter = ",";
List<String> full = new ArrayList<>();
List<String> size = new ArrayList<>();
private ArrayList<LatLng> markerCoords = new ArrayList<LatLng>();
String info;
String name;
Double lat;
Double lng;
Button emergency;
LatLng mark;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.mapAPI);
mapFragment.getMapAsync(this);
data = findViewById(R.id.fetchdata);
new fetchData(new CallbackClass()).execute();
emergency = findViewById(R.id.button);
emergency.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
}
@Override
public void onMapReady(GoogleMap googleMap) {
mapAPI = googleMap;
mapAPI.getUiSettings().setZoomControlsEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
buildGoogleApiClient();
mapAPI.setMyLocationEnabled(true);
//mapAPI.setOnMyLocationChangeListener(this);
}
} else {
buildGoogleApiClient();
mapAPI.setMyLocationEnabled(true);
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
mGoogleApiClient.connect();
}
@Override
public void onConnected(Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onLocationChanged(Location location) {
/*mLastLocation = location;
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}*/
//Place current location marker
LatLng patient = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(patient);
markerOptions.title("Patient");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE));
mCurrLocationMarker = mapAPI.addMarker(markerOptions);
//move map camera
mapAPI.animateCamera(CameraUpdateFactory.zoomTo(11));
mapAPI.moveCamera(CameraUpdateFactory.newLatLng(patient));
//stop location updates
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
public class CallbackClass implements CallbackInterface {
@Override
public void onSuccess(String callbackData) {
info = callbackData;
full = Arrays.asList(info.split(delimiter));
size = Arrays.asList(info.split(delimiter));
Integer x = 0;
while(x != size.size()){
name = full.get(x);
x += 1;
lat = Double.valueOf(full.get(x));
x += 1;
lng = Double.valueOf(full.get(x));
x += 1;
LatLng pos = new LatLng(lat, lng);
mapAPI.addMarker(new MarkerOptions().position(pos).title(name));
mark = new LatLng(lat,lng);
markerCoords.add(mark);
}
}
@Override
public void onFailure() {
}
}
}
and this is the code for parsing the JSON from the database any help would be greatly appreciated.
package com.example.defiblocator;
import android.app.Application;
import android.os.AsyncTask;
import android.widget.TextView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class fetchData extends AsyncTask <Void,Void,Void>{
CallbackInterface callbackInterface;
String data = "";
String json_url;
String singleParsed = "";
public String dataParsed = "";
String sent;
public fetchData(CallbackInterface callbackInterface) {
this.callbackInterface = callbackInterface;
}
public Integer x = 0;
@Override
protected void onPreExecute(){
json_url = "http://defiblocator.ml/json_get_data.php";
dataParsed = "";
}
@Override
protected Void doInBackground(Void... voids) {
try {
URL url = new URL(json_url);
HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = "";
while(line != null){
line = bufferedReader.readLine();
data = data + line;
}
JSONArray JA = new JSONArray(data);
for(int i =0 ; i <JA.length(); i++){
JSONObject JO = (JSONObject) JA.get(i);
singleParsed = JO.get("name") + "," + JO.get("lat") + "," +JO.get("lng") + "," ;
dataParsed = dataParsed + singleParsed ;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException | JSONException e){
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
MainActivity.data.setText(dataParsed);
callbackInterface.onSuccess(dataParsed);
}
}
Comments
Comment posted by Noah Johnson
when i tried to implement your idea i kept getting errors for .getPosition() what am I doing wrong??
Comment posted by Ariel Perez
Now i see markerCoords is an ArrayList of LatLng. I edited my answer