How to draw path as I move starting from my current location using Google Maps

43,715

Solution 1

It seems that the best implementation would be to just use an ArrayList<LatLng> to store each point given in onLocationChanged(). Then, each time you get a new point, re-draw the line.

First, import what you need for drawing the lines:

import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;

Create member variables for the ArrayList and the Polyline:

private ArrayList<LatLng> points; //added
Polyline line; //added

Initialize points in onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    points = new ArrayList<LatLng>(); //added
    //...............

Then, in onLocationChanged(), add each point you get to the ArrayList:

@Override
public void onLocationChanged(Location location) {
      double latitude = location.getLatitude();
      double longitude = location.getLongitude();
      LatLng latLng = new LatLng(latitude, longitude); //you already have this

      points.add(latLng); //added

      redrawLine(); //added

}

Taking from this answer, define your redrawLine() method.
Remove all other calls to addMarker(), since you will be calling clear() on your map, which removes all Markers and Polylines.

private void redrawLine(){

    googleMap.clear();  //clears all Markers and Polylines

    PolylineOptions options = new PolylineOptions().width(5).color(Color.BLUE).geodesic(true);
    for (int i = 0; i < points.size(); i++) {
        LatLng point = points.get(i);
        options.add(point);
    }
    addMarker(); //add Marker in current position
    line = googleMap.addPolyline(options); //add Polyline
}

Edit: You will also probably want to dial in the minimum distance in meters between location changed callbacks.

private static final String TAG = "MainActivity";
private static final long INTERVAL = 1000 * 60 * 1; //1 minute
private static final long FASTEST_INTERVAL = 1000 * 60 * 1; // 1 minute
private static final float SMALLEST_DISPLACEMENT = 0.25F; //quarter of a meter

Call setSmallestDisplacement():

protected void createLocationRequest() {
    mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(INTERVAL);
    mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
    mLocationRequest.setSmallestDisplacement(SMALLEST_DISPLACEMENT); //added
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}

That should be enough to get you started. You may need to fine-tune the frequency of location changed callbacks to get your desired result. There's probably more to it than that, but you can find the edge cases and fix them after testing.

Solution 2

I know it's pretty late for an answer, but I'll post this here for those still have the same problem.

If you want to move a marker or/and a Polyline, you don't need to remove/clear and draw again, instead you have to add PolylineOptions once and than set the new points afterwards.

Example Code:

boolean isPolyAdded = false;

Add this line of the code:

if (isPolyLoaded == false){
        polyline = map.addPolyline(lineOptions);
        isPolyLoaded = true;
    }else{
        polyline.setPoints(points);
    }

to the and of onPostExecute method

Final Code:

 @Override
    protected void onPostExecute(List<List<HashMap<String, String>>> result) {

        // Traversing through all the routes
        for(int i=0;i<result.size();i++){
            points = new ArrayList<LatLng>();
            lineOptions = new PolylineOptions();

            // Fetching i-th route
            List<HashMap<String, String>> path = result.get(i);

            // Fetching all the points in i-th route
            for(int j=0;j<path.size();j++){
                HashMap<String,String> point = path.get(j);

                double lat = Double.parseDouble(point.get("lat"));
                double lng = Double.parseDouble(point.get("lng"));
                LatLng position = new LatLng(lat, lng);

                points.add(position);
            }

            // Adding all the points in the route to LineOptions
            lineOptions.addAll(points);
            lineOptions.width(7);
            lineOptions.color(Color.BLACK);
        }

        // Drawing polyline in the Google Map for the i-th route

        if (isPolyLoaded == false){
            polyline = map.addPolyline(lineOptions);
            isPolyLoaded = true;
        }else{
            polyline.setPoints(points);
        }

    }
}
Share:
43,715
Keshav1234
Author by

Keshav1234

Updated on July 09, 2022

Comments

  • Keshav1234
    Keshav1234 almost 2 years

    I am trying to draw route as I move from my current location. I am facing a big problem in drawing route dynamically please help me to solve it. I am having marker at my current location in my map. As soon as I start moving I want the map to start drawing lines in the path I move. I do not have two fixed points. Can any one please provide me a solution to over come this. I have seen lot of answers in SO which draws path between two fixed points. But here only my initial point is fixed. I am able to get my current location in my app currently. I tried with the following code but getLocationManager() is resulting in error. i am using Android Studio.

    Updated Code:

    My Activity:

    import android.content.Context;
    import android.content.SharedPreferences;
    import android.location.Address;
    import android.location.Geocoder;
    import android.location.Location;
    import android.os.Bundle;
    import android.support.v4.app.FragmentActivity;
    import android.util.Log;
    import android.util.Xml;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import com.google.android.gms.common.ConnectionResult;
    import com.google.android.gms.common.GooglePlayServicesUtil;
    import com.google.android.gms.common.api.GoogleApiClient;
    import com.google.android.gms.common.api.PendingResult;
    import com.google.android.gms.common.api.Status;
    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.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 com.google.maps.android.ui.IconGenerator;
    
    import org.xmlpull.v1.XmlSerializer;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.StringWriter;
    import java.text.DateFormat;
    import java.util.Calendar;
    import java.util.Date;
    import java.util.List;
    import java.util.Locale;
    
    public class MainActivity extends FragmentActivity implements
            LocationListener,
            GoogleApiClient.ConnectionCallbacks,
            GoogleApiClient.OnConnectionFailedListener {
    
        private static final String TAG = "MainActivity";
        private static final long INTERVAL = 1000 * 60 * 1; //1 minute
        private static final long FASTEST_INTERVAL = 1000 * 60 * 1; // 1 minute
        private LocationRequest mLocationRequest;
        private GoogleApiClient mGoogleApiClient;
        private Location mCurrentLocation;
        private String mLastUpdateTime;
        private String city = "";
        private String country = "";
        private String area = "";
        private String title;
        private String requiredArea = "";
        private GoogleMap googleMap;
        private List<Address> addresses;
    
    
        protected void createLocationRequest() {
            mLocationRequest = new LocationRequest();
            mLocationRequest.setInterval(INTERVAL);
            mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
            mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.d(TAG, "onCreate ...............................");
            //show error dialog if GoolglePlayServices not available
            if (!isGooglePlayServicesAvailable()) {
    
                Toast.makeText(this, "Google Play Services is not available", Toast.LENGTH_LONG).show();
    
                finish();
            }
            createLocationRequest();
            mGoogleApiClient = new GoogleApiClient.Builder(this)
                    .addApi(LocationServices.API)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .build();
    
            setContentView(R.layout.activity_main);
            SupportMapFragment fm = (SupportMapFragment) getSupportFragmentManager()
                    .findFragmentById(R.id.map);
    
            googleMap = fm.getMap();
            googleMap.setMyLocationEnabled(true);
            googleMap.setOnMyLocationButtonClickListener(new GoogleMap.OnMyLocationButtonClickListener() {
                @Override
                public boolean onMyLocationButtonClick() {
    
                    Toast.makeText(getApplicationContext(), "Location button has been clicked", Toast.LENGTH_LONG).show();
                    return true;
                }
            });
            googleMap.getUiSettings().setZoomControlsEnabled(true);
            googleMap.getUiSettings().setAllGesturesEnabled(true);
    
    
        }
    
        @Override
        public void onStart() {
            super.onStart();
            Log.d(TAG, "onStart fired ..............");
            mGoogleApiClient.connect();
        }
    
        @Override
        public void onStop() {
            super.onStop();
            Log.d(TAG, "onStop fired ..............");
            mGoogleApiClient.disconnect();
            Log.d(TAG, "isConnected ...............: " + mGoogleApiClient.isConnected());
        }
    
        private boolean isGooglePlayServicesAvailable() {
            int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
            if (ConnectionResult.SUCCESS == status) {
                return true;
            } else {
                GooglePlayServicesUtil.getErrorDialog(status, this, 0).show();
                Toast.makeText(getApplicationContext(), "Google Play Services is not Available", Toast.LENGTH_LONG).show();
                return false;
            }
        }
    
        @Override
        public void onConnected(Bundle bundle) {
            Log.d(TAG, "onConnected - isConnected ...............: " + mGoogleApiClient.isConnected());
            startLocationUpdates();
        }
    
        protected void startLocationUpdates() {
            PendingResult<Status> pendingResult = LocationServices.FusedLocationApi.requestLocationUpdates(
                    mGoogleApiClient, mLocationRequest, this);
            Log.d(TAG, "Location update started ..............: ");
        }
    
        @Override
        public void onConnectionSuspended(int i) {
    
        }
    
        @Override
        public void onConnectionFailed(ConnectionResult connectionResult) {
            Log.d(TAG, "Connection failed: " + connectionResult.toString());
        }
    
        @Override
        public void onLocationChanged(Location location) {
            Log.d(TAG, "Firing onLocationChanged..............................................");
            mCurrentLocation = location;
            mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
            addMarker();
            float accuracy = location.getAccuracy();
            Log.d("iFocus", "The amount of accuracy is " + accuracy);
            double latitude = location.getLatitude();
            double longitude = location.getLongitude();
            Bundle extras = location.getExtras();
            Boolean has = location.hasAccuracy();
            String provider = location.getProvider();
            Long time = location.getTime();
    
    //        Location locationB = new Location("Begur");
    //        double lati = 12.8723;
    //        double longi =  77.6329;
    //        locationB.setLatitude(lati);
    //        locationB.setLongitude(longi);
    //        Float distance = location.distanceTo(locationB);
    
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(time);
    
            int mYear = calendar.get(Calendar.YEAR);
            int mMonth = calendar.get(Calendar.MONTH) + 1;
            int mDay = calendar.get(Calendar.DAY_OF_MONTH);
    
            String formattedTime = mDay + ":" + mMonth + ":" + mYear;
            Log.d("iFocus", "The name of provider is " + provider);
            Log.d("iFocus", "The value of has is " + has);
            Log.d("iFocus", "The value of extras is " + extras);
            Log.d("iFocus", "The value of Month is " + mMonth);
            Log.d("iFocus", "The value of Day is " + mDay);
            Log.d("iFocus", "The value of Year is " + mYear);
            Log.d("iFocus", "The value of Time is " + formattedTime);
            //Log.d("iFocus", "The value of distance is "+distance);
    
            LatLng latLng = new LatLng(latitude, longitude);
    
            Geocoder geocoder = new Geocoder(this, Locale.getDefault());
    
            try {
                addresses = geocoder.getFromLocation(latitude, longitude, 1);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            String cityName = addresses.get(0).getAddressLine(0);
            String stateName = addresses.get(0).getAddressLine(1);
            String countryName = addresses.get(0).getAddressLine(2);
    
            String[] splittedStateName = stateName.split(",");
            requiredArea = splittedStateName[2];
            Log.d("iFocus", "The value of required area is " + requiredArea);
    
            city = addresses.get(0).getLocality();
            area = addresses.get(0).getSubLocality();
            String adminArea = addresses.get(0).getAdminArea();
            String premises = addresses.get(0).getPremises();
            String subAdminArea = addresses.get(0).getSubAdminArea();
            String featureName = addresses.get(0).getFeatureName();
            String phone = addresses.get(0).getPhone();
            country = addresses.get(0).getCountryName();
            Log.d("iFocus", "The name of city is " + city);
            Log.d("iFocus", "The name of area is " + area);
            Log.d("iFocus", "The name of country is " + country);
            Log.d("iFocus", "The value of cityName is " + cityName);
            Log.d("iFocus", "The value of StateName is " + stateName);
            Log.d("iFocus", "The value of CountryName is " + countryName);
    
            Toast.makeText(this, cityName + " " + stateName + " " + countryName, Toast.LENGTH_LONG).show();
    
            SharedPreferences sharedPreferences = getSharedPreferences("MyValues", MODE_PRIVATE);
            SharedPreferences.Editor editor = sharedPreferences.edit();
            editor.putString("CITY", cityName);
            editor.putString("STATE", stateName);
            editor.putString("COUNTRY", countryName);
            editor.commit();
    
            TextView mapTitle = (TextView) findViewById(R.id.textViewTitle);
    
            if (requiredArea != "" && city != "" && country != "") {
                title = mLastUpdateTime.concat(", " + requiredArea).concat(", " + city).concat(", " + country);
            }
            else {
                title = mLastUpdateTime.concat(", " + area).concat(", " + city).concat(", " + country);
            }
            mapTitle.setText(title);
            addMarker();// newly added
    
            final String xmlFile = "userData.xml";
    
            try {
                // FileOutputStream fos = new  FileOutputStream("userData.xml");
                FileOutputStream fos = openFileOutput(xmlFile, Context.MODE_PRIVATE);
                XmlSerializer xmlSerializer = Xml.newSerializer();
                StringWriter writer = new StringWriter();
                xmlSerializer.setOutput(writer);
                xmlSerializer.startDocument("UTF-8", true);
                xmlSerializer.startTag(null, "userData");
                xmlSerializer.startTag(null, "Time");
                xmlSerializer.text(mLastUpdateTime);
                xmlSerializer.endTag(null, "Time");
                xmlSerializer.startTag(null, "Area");
                if (requiredArea != "") {
                    xmlSerializer.text(requiredArea);
                }
                else {
                    xmlSerializer.text(area);
                }
                xmlSerializer.endTag(null, "Area");
                xmlSerializer.startTag(null, "City");
                xmlSerializer.text(city);
                xmlSerializer.endTag(null, "City");
                xmlSerializer.endTag(null, "userData");
                xmlSerializer.endDocument();
                xmlSerializer.flush();
                String dataWrite = writer.toString();
                fos.write(dataWrite.getBytes());
                fos.close();
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalStateException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            String dir = getFilesDir().getAbsolutePath();
            Log.d("Pana", "The value of Dir is "+dir);
    
        }
    
        private void addMarker() {
            MarkerOptions options = new MarkerOptions();
    
            // following four lines requires 'Google Maps Android API Utility Library'
            // https://developers.google.com/maps/documentation/android/utility/
            // I have used this to display the time as title for location markers
            // you can safely comment the following four lines but for this info
            IconGenerator iconFactory = new IconGenerator(this);
            iconFactory.setStyle(IconGenerator.STYLE_PURPLE);
            // options.icon(BitmapDescriptorFactory.fromBitmap(iconFactory.makeIcon(mLastUpdateTime + requiredArea + city)));
            options.icon(BitmapDescriptorFactory.fromBitmap(iconFactory.makeIcon(requiredArea + ", " + city)));
            options.anchor(iconFactory.getAnchorU(), iconFactory.getAnchorV());
            LatLng currentLatLng = new LatLng(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude());
            options.position(currentLatLng);
            Marker mapMarker = googleMap.addMarker(options);
            long atTime = mCurrentLocation.getTime();
            mLastUpdateTime = DateFormat.getTimeInstance().format(new Date(atTime));
            String title = mLastUpdateTime.concat(", " + requiredArea).concat(", " + city).concat(", " + country);
            mapMarker.setTitle(title);
    
    
            TextView mapTitle = (TextView) findViewById(R.id.textViewTitle);
            mapTitle.setText(title);
    
            Log.d(TAG, "Marker added.............................");
            googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng,
                    13));
            Log.d(TAG, "Zoom done.............................");
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            stopLocationUpdates();
        }
    
        protected void stopLocationUpdates() {
            LocationServices.FusedLocationApi.removeLocationUpdates(
                    mGoogleApiClient, this);
            Log.d(TAG, "Location update stopped .......................");
        }
    
        @Override
        public void onResume() {
            super.onResume();
            if (mGoogleApiClient.isConnected()) {
                startLocationUpdates();
                Log.d(TAG, "Location update resumed .....................");
            }
        }
    }
    

    I am trying to add this method in my code to draw line but its giving error in getLocationManager();

    private void addLocationListener(LocationListener locationListener) {
        LocationProvider locationProvider = getLocationManager().getProvider(LocationManager.GPS_PROVIDER);
        getLocationManager().requestLocationUpdates(locationProvider.getName(), LOCATION_UPDATE_INTERVAL,
                    LOCATION_UPDATE_MIN_DISTANCE, locationListener);
    }
    
    private LocationManager getLocationManager() {
        return (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
    }
    
    private void startGpsListening(Location start) {
        this.startLocation = start;
        addLocationListener(new MyLocationListener());
    }
    
    private Location startLocation = new Location("");
    
    private class MyLocationListener extends LocationListener {
    
        public void onLocationChanged(Location location) {
    
        }
        ...
    }