How do I get the current GPS location programmatically in Android?

前端 未结 22 2658
梦谈多话
梦谈多话 2020-11-21 04:42

I need to get my current location using GPS programmatically. How can i achieve it?

相关标签:
22条回答
  • 2020-11-21 05:08

    Since I didn't like some of the code in the other answers, here's my simple solution. This solution is meant to be usable in an Activity or Service to track the location. It makes sure that it never returns data that's too stale unless you explicitly request stale data. It can be run in either a callback mode to get updates as we receive them, or in poll mode to poll for the most recent info.

    Generic LocationTracker interface. Allows us to have multiple types of location trackers and plug the appropriate one in easily:

    package com.gabesechan.android.reusable.location;
    
    import android.location.Location;
    
    public interface LocationTracker {
        public interface LocationUpdateListener{
            public void onUpdate(Location oldLoc, long oldTime, Location newLoc, long newTime);
        }
    
        public void start();
        public void start(LocationUpdateListener update);
    
        public void stop();
    
        public boolean hasLocation();
    
        public boolean hasPossiblyStaleLocation();
    
        public Location getLocation();
    
        public Location getPossiblyStaleLocation();
    
    }
    

    ProviderLocationTracker- this class will track the location for either GPS or NETWORK.

    package com.gabesechan.android.reusable.location;
    
    import android.content.Context;
    import android.location.Location;
    import android.location.LocationListener;
    import android.location.LocationManager;
    import android.os.Bundle;
    
    public class ProviderLocationTracker implements LocationListener, LocationTracker {
    
        // The minimum distance to change Updates in meters
        private static final long MIN_UPDATE_DISTANCE = 10; 
    
        // The minimum time between updates in milliseconds
        private static final long MIN_UPDATE_TIME = 1000 * 60; 
    
        private LocationManager lm;
    
        public enum ProviderType{
            NETWORK,
            GPS
        };    
        private String provider;
    
        private Location lastLocation;
        private long lastTime;
    
        private boolean isRunning;
    
        private LocationUpdateListener listener;
    
        public ProviderLocationTracker(Context context, ProviderType type) {
            lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
            if(type == ProviderType.NETWORK){
                provider = LocationManager.NETWORK_PROVIDER;
            }
            else{
                provider = LocationManager.GPS_PROVIDER;
            }
        }
    
        public void start(){
            if(isRunning){
                //Already running, do nothing
                return;
            }
    
            //The provider is on, so start getting updates.  Update current location
            isRunning = true;
            lm.requestLocationUpdates(provider, MIN_UPDATE_TIME, MIN_UPDATE_DISTANCE, this);
            lastLocation = null;
            lastTime = 0;
            return;
        }
    
        public void start(LocationUpdateListener update) {
            start();
            listener = update;
    
        }
    
    
        public void stop(){
            if(isRunning){
                lm.removeUpdates(this);
                isRunning = false;
                listener = null;
            }
        }
    
        public boolean hasLocation(){
            if(lastLocation == null){
                return false;
            }
            if(System.currentTimeMillis() - lastTime > 5 * MIN_UPDATE_TIME){
                return false; //stale
            }
            return true;
        }
    
        public boolean hasPossiblyStaleLocation(){
            if(lastLocation != null){
                return true;
            }
            return lm.getLastKnownLocation(provider)!= null;
        }
    
        public Location getLocation(){
            if(lastLocation == null){
                return null;
            }
            if(System.currentTimeMillis() - lastTime > 5 * MIN_UPDATE_TIME){
                return null; //stale
            }
            return lastLocation;
        }
    
        public Location getPossiblyStaleLocation(){
            if(lastLocation != null){
                return lastLocation;
            }
            return lm.getLastKnownLocation(provider);
        }
    
        public void onLocationChanged(Location newLoc) {
            long now = System.currentTimeMillis();
            if(listener != null){
                listener.onUpdate(lastLocation, lastTime, newLoc, now);
            }
            lastLocation = newLoc;
            lastTime = now;
        }
    
        public void onProviderDisabled(String arg0) {
    
        }
    
        public void onProviderEnabled(String arg0) {
    
        }
    
        public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
        }
    }
    

    The is the FallbackLocationTracker, which will track by both GPS and NETWORK, and use whatever location is more accurate.

    package com.gabesechan.android.reusable.location;
    
    import android.content.Context;
    import android.location.Location;
    import android.location.LocationManager;
    
    public class FallbackLocationTracker  implements LocationTracker, LocationTracker.LocationUpdateListener {
    
    
        private boolean isRunning;
    
        private ProviderLocationTracker gps;
        private ProviderLocationTracker net;
    
        private LocationUpdateListener listener;
    
        Location lastLoc;
        long lastTime;
    
        public FallbackLocationTracker(Context context) {
            gps = new ProviderLocationTracker(context, ProviderLocationTracker.ProviderType.GPS);
            net = new ProviderLocationTracker(context, ProviderLocationTracker.ProviderType.NETWORK);
        }
    
        public void start(){
            if(isRunning){
                //Already running, do nothing
                return;
            }
    
            //Start both
            gps.start(this);
            net.start(this);
            isRunning = true;
        }
    
        public void start(LocationUpdateListener update) {
            start();
            listener = update;
        }
    
    
        public void stop(){
            if(isRunning){
                gps.stop();
                net.stop();
                isRunning = false;
                listener = null;
            }
        }
    
        public boolean hasLocation(){
            //If either has a location, use it
            return gps.hasLocation() || net.hasLocation();
        }
    
        public boolean hasPossiblyStaleLocation(){
            //If either has a location, use it
            return gps.hasPossiblyStaleLocation() || net.hasPossiblyStaleLocation();
        }
    
        public Location getLocation(){
            Location ret = gps.getLocation();
            if(ret == null){
                ret = net.getLocation();
            }
            return ret;
        }
    
        public Location getPossiblyStaleLocation(){
            Location ret = gps.getPossiblyStaleLocation();
            if(ret == null){
                ret = net.getPossiblyStaleLocation();
            }
            return ret;
        }
    
        public void onUpdate(Location oldLoc, long oldTime, Location newLoc, long newTime) {
            boolean update = false;
    
            //We should update only if there is no last location, the provider is the same, or the provider is more accurate, or the old location is stale
            if(lastLoc == null){
                update = true;
            }
            else if(lastLoc != null && lastLoc.getProvider().equals(newLoc.getProvider())){
                update = true;
            }
            else if(newLoc.getProvider().equals(LocationManager.GPS_PROVIDER)){
                update = true;
            }
            else if (newTime - lastTime > 5 * 60 * 1000){
                update = true;
            }
    
            if(update){
                if(listener != null){
                    listener.onUpdate(lastLoc, lastTime, newLoc, newTime);                  
                }
                lastLoc = newLoc;
                lastTime = newTime;
            }
    
        }
    }
    

    Since both implement the LocationTracker interface, you can easily change your mind about which one to use. To run the class in poll mode, just call start(). To run it in update mode, call start(Listener).

    Also take a look at my blog post on the code

    0 讨论(0)
  • 2020-11-21 05:11

    Here is additional information for other answers.

    Since Android has

    GPS_PROVIDER and NETWORK_PROVIDER
    

    you can register to both and start fetch events from onLocationChanged(Location location) from two at the same time. So far so good. Now the question do we need two results or we should take the best. As I know GPS_PROVIDER results have better accuracy than NETWORK_PROVIDER.

    Let's define Location field:

    private Location currentBestLocation = null;
    

    Before we start listen on Location change we will implement the following method. This method returns the last known location, between the GPS and the network one. For this method newer is best.

    /**
     * @return the last know best location
     */
    private Location getLastBestLocation() {
        Location locationGPS = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        Location locationNet = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
    
        long GPSLocationTime = 0;
        if (null != locationGPS) { GPSLocationTime = locationGPS.getTime(); }
    
        long NetLocationTime = 0;
    
        if (null != locationNet) {
            NetLocationTime = locationNet.getTime();
        }
    
        if ( 0 < GPSLocationTime - NetLocationTime ) {
            return locationGPS;
        }
        else {
            return locationNet;
        }
    }
    

    Each time when we retrieve a new location we will compare it with our previous result.

    ...
    static final int TWO_MINUTES = 1000 * 60 * 2;
    ...
    

    I add a new method to onLocationChanged:

    @Override
    public void onLocationChanged(Location location) {
    
        makeUseOfNewLocation(location);
    
        if(currentBestLocation == null){
            currentBestLocation = location;
        }
    
        ....
    }
    
    
    /**
     * This method modify the last know good location according to the arguments.
     *
     * @param location The possible new location.
     */
    void makeUseOfNewLocation(Location location) {
        if ( isBetterLocation(location, currentBestLocation) ) {
            currentBestLocation = location;
        }
    }
    
    ....
    
    /** Determines whether one location reading is better than the current location fix
     * @param location  The new location that you want to evaluate
     * @param currentBestLocation  The current location fix, to which you want to compare the new one.
     */
    protected boolean isBetterLocation(Location location, Location currentBestLocation) {
        if (currentBestLocation == null) {
            // A new location is always better than no location
            return true;
        }
    
        // Check whether the new location fix is newer or older
        long timeDelta = location.getTime() - currentBestLocation.getTime();
        boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
        boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
        boolean isNewer = timeDelta > 0;
    
        // If it's been more than two minutes since the current location, use the new location,
        // because the user has likely moved.
        if (isSignificantlyNewer) {
            return true;
            // If the new location is more than two minutes older, it must be worse.
        } else if (isSignificantlyOlder) {
            return false;
        }
    
        // Check whether the new location fix is more or less accurate
        int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
        boolean isLessAccurate = accuracyDelta > 0;
        boolean isMoreAccurate = accuracyDelta < 0;
        boolean isSignificantlyLessAccurate = accuracyDelta > 200;
    
        // Check if the old and new location are from the same provider
        boolean isFromSameProvider = isSameProvider(location.getProvider(),
                                                    currentBestLocation.getProvider());
    
        // Determine location quality using a combination of timeliness and accuracy
        if (isMoreAccurate) {
            return true;
        } else if (isNewer && !isLessAccurate) {
            return true;
        } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
            return true;
        }
        return false;
    }
    
    // Checks whether two providers are the same
    private boolean isSameProvider(String provider1, String provider2) {
        if (provider1 == null) {
            return provider2 == null;
        }
        return provider1.equals(provider2);
    }
    
    ....
    
    0 讨论(0)
  • 2020-11-21 05:12

    Best way to fetch location is below

    // put dependancy
     implementation 'com.google.android.gms:play-services-location:11.0.4'
    
    // PUT permissions in Menifest
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 
    
    
    // create a Java file as below
    
    public class SingleShotLocationProvider {
    
      public static interface LocationCallback {
          public void onNewLocationAvailable(GPSCoordinates location);
      }
    
       // calls back to calling thread, note this is for low grain: if you want higher precision, swap the
       // contents of the else and if. Also be sure to check gps permission/settings are allowed.
       // call usually takes <10ms
    
      public static void requestSingleUpdate(final Context context, final LocationCallback callback) {
        final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        if (isNetworkEnabled) {
            Criteria criteria = new Criteria();
            criteria.setAccuracy(Criteria.ACCURACY_COARSE);
            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                    ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
    
                return;
            }
            locationManager.requestSingleUpdate(criteria, new LocationListener() {
                @Override
                public void onLocationChanged(Location location) {
                    callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude()));
                }
    
                @Override
                public void onStatusChanged(String provider, int status, Bundle extras) {
                }
    
                @Override
                public void onProviderEnabled(String provider) {
                }
    
                @Override
                public void onProviderDisabled(String provider) {
                }
            }, null);
         } else {
            boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            if (isGPSEnabled) {
                Criteria criteria = new Criteria();
                criteria.setAccuracy(Criteria.ACCURACY_FINE);
                locationManager.requestSingleUpdate(criteria, new LocationListener() {
                    @Override
                    public void onLocationChanged(Location location) {
                        callback.onNewLocationAvailable(new GPSCoordinates(location.getLatitude(), location.getLongitude()));
                    }
    
                    @Override public void onStatusChanged(String provider, int status, Bundle extras) { }
                    @Override public void onProviderEnabled(String provider) { }
                    @Override public void onProviderDisabled(String provider) { }
                }, null);
            }
         }
      }
    
    
      // consider returning Location instead of this dummy wrapper class
      public static class GPSCoordinates {
         public float longitude = -1;
         public float latitude = -1;
    
         public GPSCoordinates(float theLatitude, float theLongitude) {
            longitude = theLongitude;
            latitude = theLatitude;
         }
    
         public GPSCoordinates(double theLatitude, double theLongitude) {
            longitude = (float) theLongitude;
            latitude = (float) theLatitude;
         }
      }
    
    }
    // FILE FINISHED
    
    
    // FETCH LOCATION FROM ACTIVITY AS BELOW
    public void getLocation(Context context) {
        MyApplication.log(LOG_TAG, "getLocation() ");
    
        SingleShotLocationProvider.requestSingleUpdate(context,
                new SingleShotLocationProvider.LocationCallback() {
                    @Override
                    public void onNewLocationAvailable(SingleShotLocationProvider.GPSCoordinates loc) {
                        location = loc;
                        MyApplication.log(LOG_TAG, "getLocation() LAT: " + location.latitude + ", LON: " + location.longitude);               
                    }
                });
    }
    
    0 讨论(0)
  • 2020-11-21 05:16

    Simple and easy way,

    Get location using https://github.com/sachinvarma/EasyLocation.

    Step 1: Just call

    new EasyLocationInit(MainActivity.this, timeInterval, fastestTimeInterval, runAsBackgroundService);
    

    timeInterval -> setInterval(long)(inMilliSeconds) means - set the interval in which you want to get locations.

    fastestTimeInterval -> setFastestInterval(long)(inMilliSeconds) means - if a location is available sooner you can get it. (i.e. another app is using the location services).

    runAsBackgroundService = True -> (Service will run in Background and updates Frequently(according to the timeInterval and fastestTimeInterval)) runAsBackgroundService = False -> (Service will getDestroyed after a successful location update )

    Step 2: Prepare EventBus subscribers: Declare and annotate your subscribing method, optionally specify a thread mode:

    eg:

         @Override
         public void onStart() {
             super.onStart();
             EventBus.getDefault().register(this);
         }
    
         @Override
         public void onStop() {
             super.onStop();
             EventBus.getDefault().unregister(this);
         }
    
      @SuppressLint("SetTextI18n")
      @Subscribe
      public void getEvent(final Event event) {
    
        if (event instanceof LocationEvent) {
          if (((LocationEvent) event).location != null) {
            ((TextView) findViewById(R.id.tvLocation)).setText("The Latitude is "
              + ((LocationEvent) event).location.getLatitude()
              + " and the Longitude is "
              + ((LocationEvent) event).location.getLongitude());
          }
        }
      }
    

    That's all.

    Hope it will help someone in future.

    0 讨论(0)
提交回复
热议问题