How to locate the nearest marker to a user?

Viewed 56

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);

    }



}
1 Answers

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 


Related