Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get continuous location updates in Android like in Google Maps?

I'm building a friend tracking android app. While my friend activated the app and goes away along with his GPS and cellular data on, I need to track him on my device. That's the concept.

I've implemented LocationListener class and now I can get the last updated location either from Gps or Network but is not updated unless I launch Google Maps and return to my application. After googling, I learned that location cache is updated only by GMaps.!

  1. Is there an alternate way to continuously update location?
  2. What if when I need to get continues location after the device locked without making use of Wakelock?

This is my location listener class:

package com.amazinginside;

/** AMAZING LOCATION SUPPORT CLASS, Devoloped By SANGEETH NANDAKUMAR */

import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;

public class AmazingLocation extends Service implements LocationListener
{
    private final Context mContext;
    boolean isGPSEnabled = false;
    boolean isNetworkEnabled = false;
    boolean canGetLocation = false;

    Location location;
    double latitude=0.0;
    double longitude=0.0;

    //MINIMUM DISTANCE FOR UPDATE (meters)
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 0; // 0 Meters

    //MINIMUM TIME BETWEEN UPDATES
    private static final long MIN_TIME_BW_UPDATES = 1000 * 0; // 0 Seconds

    //LOCATION MANAGER
    protected LocationManager locationManager;

    //CONSTRUCTOR
    public AmazingLocation(Context context)
    {
        this.mContext = context;
        getLocation();
    }

    //LOCATION PROVISION
    public Location getLocation()
    {
        try
        {
            //GET LOCATION MANAGER
            locationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);
            //CHECK GPS STATE
            isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
            //CHECK NETWORK STATE
            isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

            if (!isGPSEnabled && !isNetworkEnabled)
            {
                //NO LOCATION PROVIDERS
            }
            else
            {
                this.canGetLocation = true;

                /** GET LOCATION FROM NETWORK */
                //FIRST GET LOCATION FROM NETWORK
                if (isNetworkEnabled)
                {
                    //REQUEST LOCATION
                    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                    if (locationManager != null)
                    {
                        //START WITH LAST KNOWN LOCATION
                        location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                        //EXTRACT LOCATION
                        if (location != null)
                        {
                            latitude = location.getLatitude();
                            longitude = location.getLongitude();
                        }
                    }
                }

                /** GET LOCATION FROM GPS SENSOR */
                //THEN GET LOCATION FROM GPS
                if (isGPSEnabled)
                {
                    if (location == null)
                    {
                        //REQUEST GPS LOCATION
                        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                        if (locationManager != null)
                        {
                            //EXTRACT LAST KNOWN LOCATION
                            location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                            //RETURN LOCATION
                            if (location != null)
                            {
                                latitude = location.getLatitude();
                                longitude = location.getLongitude();
                            }
                        }
                    }
                }
            }

        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return location;
    }

    //STOP GPS SENSOR
    public void stopUsingGPS()
    {
        if(locationManager != null)
        {
            locationManager.removeUpdates(AmazingLocation.this);
        }
    }

    //EXTRACT LATTITUDE
    public double getLatitude()
    {
        if(location != null)
        {
            latitude = location.getLatitude();
        }

        // return latitude
        return latitude;
    }

    //EXTACT LONGITUDE
    public double getLongitude()
    {
        if(location != null)
        {
            longitude = location.getLongitude();
        }

        // return longitude
        return longitude;
    }

    //CAN I GET THE LOCATION.?
    public AmazingStatus canGetLocation()
    {
        AmazingStatus status=new AmazingStatus();
        if(this.canGetLocation)
        {
            status.setStatus(true);
            status.setErrorcode(0);
            status.setErrormsg("Task completed");
        }
        else
        {
            status.setStatus(false);
            status.setErrorcode(145);
            status.setErrormsg("Please turn on GPS access manually");
        }
        return status;
    }

    //SHOW LOCATION SETTINGS
    public AmazingStatus showSettingsAlert()
    {
        final AmazingStatus status=new AmazingStatus();
        AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
        alertDialog.setTitle("REQUIRES LOCATION ACCESS");
        alertDialog.setMessage("Please allow GPS access to this app");

        //POSSITIVE REPLY
        alertDialog.setPositiveButton("Allow", new DialogInterface.OnClickListener()
        {
            public void onClick(DialogInterface dialog,int which)
            {
                Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                mContext.startActivity(intent);
                status.setStatus(true);
                status.setErrorcode(0);
                status.setErrormsg("Task completed");
            }
        });

        //NEGATIVE REPLY
        alertDialog.setNegativeButton("Deny", new DialogInterface.OnClickListener()
        {
            public void onClick(DialogInterface dialog, int which)
            {
                status.setStatus(false);
                status.setErrorcode(408);
                status.setErrormsg("User denied permission");
                dialog.cancel();
            }
        });

        // Showing Alert Message
        alertDialog.show();
        return status;
    }

    //UNUSED OVERRIDE METHORDS...
    @Override
    public void onLocationChanged(Location location)
    {
        getLocation();
    }

    @Override
    public void onProviderDisabled(String provider)
    {
    }

    @Override
    public void onProviderEnabled(String provider)
    {
        getLocation();
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras)
    {
        getLocation();
    }

    @Override
    public IBinder onBind(Intent arg0)
    {
        return null;
    }

}

This my onCreate() method:

@Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //CREATE A BUTTON HANDLER
    Button start_btn=(Button)findViewById(R.id.start_location_streaming);
    //ON BUTTON CLICK EVENT
    start_btn.setOnClickListener(new View.OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            //REPEAT A METHORD AT SPECIFIC INTERVALS
            Timer myTimer = new Timer();
            myTimer.schedule(new TimerTask()
            {
                @Override
                public void run()
                {
                    TimerMethod();
                }

            }, 0, 8000);
        }
    });  }

These are other methods:

private void TimerMethod()
{
    //START METHORD
    this.runOnUiThread(Timer_Tick);
}

//LOCATION REPORTING METHORD
private Runnable Timer_Tick = new Runnable()
{
    public void run()
    {
        Toast.makeText(MainActivity.this, "Current latitude : "+Double.toString(getLocation().latitude), Toast.LENGTH_SHORT).show();
        Toast.makeText(MainActivity.this, "Current longitude : "+Double.toString(getLocation().longitude), Toast.LENGTH_SHORT).show();
    }
};

private LatLng getLocation()
{
    //CREATE A LOCATION CLASS INSTANCE
    AmazingLocation gps = new AmazingLocation(this);
    //RETRIVE LOCATION
    double latitude = gps.getLatitude();
    double longitude = gps.getLongitude();
    //RETURN LOCATION
    LatLng loc=new LatLng(latitude,longitude);
    return loc;
}  

Now the problem is, the toast just shows previously known the location and not updating unless I opened Google Maps and returned.

Any help will be great for me.

like image 217
Sangeeth Nandakumar Avatar asked Jan 06 '17 07:01

Sangeeth Nandakumar


People also ask

How often does location update on Android?

Location updates are provided to background apps only a few times each hour. Note: If your app is running on a device with Google Play services installed, it is highly recommended that you use the Fused Location Provider (FLP) instead.

Which method is best suited for getting location updates?

Make a location request Once a location request is in place you can start the regular updates by calling requestLocationUpdates() . Depending on the form of the request, the fused location provider either invokes the LocationCallback.

How can I get real time location in Android?

There are two ways to get the current location of any Android device: Android's Location Manager API. Fused Location Provider: Google Play Services Location APIs.

How often does Google update phone location?

In the new design, location sharing is set to 1 hour by default with options to increase or decrease depending upon your usage. According to 9to5Google, the change is being rolled out on Google Maps for Android with the new versions.


3 Answers

Use Fused location provider in Android set your interval in that:

For an example create your activity like this:

public class LocationActivity extends Activity implements         LocationListener,         GoogleApiClient.ConnectionCallbacks,         GoogleApiClient.OnConnectionFailedListener {      private static final String TAG = "LocationActivity";     private static final long INTERVAL = 1000 * 10;     private static final long FASTEST_INTERVAL = 1000 * 5;     Button btnFusedLocation;     TextView tvLocation;     LocationRequest mLocationRequest;     GoogleApiClient mGoogleApiClient;     Location mCurrentLocation;     String mLastUpdateTime;      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()) {             finish();         }         createLocationRequest();         mGoogleApiClient = new GoogleApiClient.Builder(this)                 .addApi(LocationServices.API)                 .addConnectionCallbacks(this)                 .addOnConnectionFailedListener(this)                 .build();          setContentView(R.layout.activity_main);         tvLocation = (TextView) findViewById(R.id.tvLocation);          btnFusedLocation = (Button) findViewById(R.id.btnShowLocation);         btnFusedLocation.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View arg0) {                 updateUI();             }         });      }      @Override     public void onStart() {         super.onStart();         if (mGoogleApiClient.isConnected()) {             startLocationUpdates();             Log.d(TAG, "Location update resumed .....................");         }     }      @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();             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());         updateUI();     }      private void updateUI() {         Log.d(TAG, "UI update initiated .............");         if (null != mCurrentLocation) {             String lat = String.valueOf(mCurrentLocation.getLatitude());             String lng = String.valueOf(mCurrentLocation.getLongitude());             tvLocation.setText("At Time: " + mLastUpdateTime + "\n" +                     "Latitude: " + lat + "\n" +                     "Longitude: " + lng + "\n" +                     "Accuracy: " + mCurrentLocation.getAccuracy() + "\n" +                     "Provider: " + mCurrentLocation.getProvider());         } else {             Log.d(TAG, "location is null ...............");         }     }      @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 .....................");         }     } } 

Google play services required:

like image 181
Pushpendra Avatar answered Sep 21 '22 18:09

Pushpendra


To get continiuos location update, you can refer to the above provided answers .

But You can also make use of LocationServices which is faster than other approaches and much easy and efficient to get location.

This approach is quit long but kindly follow all the provided steps

So let me provide a brief working :

  1. Add these two dependencies in your gradle app file

    implementation 'com.google.android.gms:play-services-maps:17.0.0' implementation 'com.google.android.gms:play-services-location:17.0.0'

  2. Add these permissions in the manifest file outside applicationtag

  3. Declare variable outside onCreate

    private FusedLocationProviderClient fusedLocationClient; private LocationRequest mLocationRequest; private LocationCallback mlocationCallback; private LocationSettingsRequest.Builder builder; private static final int REQUEST_CHECK_SETTINGS = 102;

  4. Now inside onCreate :

    fusedLocationClient = LocationServices.getFusedLocationProviderClient(this); fetchLastLocation(); mlocationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { if (locationResult == null) { return; } for (Location location : locationResult.getLocations()) { // Update UI with location data // ... Log.e("CONTINIOUSLOC: ", location.toString()); } }; };

    mLocationRequest = createLocationRequest(); builder = new LocationSettingsRequest.Builder() .addLocationRequest(mLocationRequest); checkLocationSetting(builder);

  5. No define fetchLastLocation method

    private void fetchLastLocation() {

         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {          if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {              // TODO: Consider calling              //    Activity#requestPermissions              // here to request the missing permissions, and then overriding              //   public void onRequestPermissionsResult(int requestCode, String[] permissions,              //                                          int[] grantResults)              // to handle the case where the user grants the permission. See the documentation              // for Activity#requestPermissions for more details. 

    // Toast.makeText(MainActivity.this, "Permission not granted, Kindly allow permission", Toast.LENGTH_LONG).show(); showPermissionAlert(); return; } } fusedLocationClient.getLastLocation() .addOnSuccessListener(this, new OnSuccessListener() { @Override public void onSuccess(Location location) { // Got last known location. In some rare situations this can be null. if (location != null) { // Logic to handle location object Log.e("LAST LOCATION: ", location.toString()); // You will get your last location here } } });

     } 
  6. Now define other two method for permission request

    @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case 123: { // If request is cancelled, the result arrays are empty. if (grantResults[0] == PackageManager.PERMISSION_DENIED) { // permission was denied, show alert to explain permission showPermissionAlert(); }else{ //permission is granted now start a background service if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) { fetchLastLocation(); } } } } }

     private void showPermissionAlert(){      if (ActivityCompat.checkSelfPermission(MainHomeActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED              && ActivityCompat.checkSelfPermission(MainHomeActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {          ActivityCompat.requestPermissions(MainHomeActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 123);      }  } 
  7. now define createLocationRequest method and checkLocationSetting method :

    protected LocationRequest createLocationRequest() { LocationRequest mLocationRequest = LocationRequest.create(); mLocationRequest.setInterval(30000); mLocationRequest.setFastestInterval(10000); mLocationRequest.setSmallestDisplacement(30); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); return mLocationRequest; }

    private void checkLocationSetting(LocationSettingsRequest.Builder builder) {

         SettingsClient client = LocationServices.getSettingsClient(this);      Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());       task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {          @Override          public void onSuccess(LocationSettingsResponse locationSettingsResponse) {              // All location settings are satisfied. The client can initialize              // location requests here.              // ...              startLocationUpdates();              return;          }      });       task.addOnFailureListener(this, new OnFailureListener() {          @Override          public void onFailure(@NonNull final Exception e) {              if (e instanceof ResolvableApiException) {                  // Location settings are not satisfied, but this can be fixed                  AlertDialog.Builder builder1 = new AlertDialog.Builder(mContext);                  builder1.setTitle("Continious Location Request");                  builder1.setMessage("This request is essential to get location update continiously");                  builder1.create();                  builder1.setPositiveButton("OK", new DialogInterface.OnClickListener() {                      @Override                      public void onClick(DialogInterface dialog, int which) {                          ResolvableApiException resolvable = (ResolvableApiException) e;                          try {                              resolvable.startResolutionForResult(MainHomeActivity.this,                                      REQUEST_CHECK_SETTINGS);                          } catch (IntentSender.SendIntentException e1) {                              e1.printStackTrace();                          }                      }                  });                  builder1.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {                      @Override                      public void onClick(DialogInterface dialog, int which) {                          Toast.makeText(mContext, "Location update permission not granted", Toast.LENGTH_LONG).show();                      }                  });                  builder1.show();              }          }      });   }   @Override  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {      if (requestCode == REQUEST_CHECK_SETTINGS) {          if (resultCode == RESULT_OK) {              // All location settings are satisfied. The client can initialize              // location requests here.               startLocationUpdates();          }          else {              checkLocationSetting(builder);          }      }  } 
  8. now atlast define startLocationUpdates and stopLocationUpdates method :

    public void startLocationUpdates() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // Activity#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for Activity#requestPermissions for more details. return; } } fusedLocationClient.requestLocationUpdates(mLocationRequest, mlocationCallback, null /* Looper */); }

    private void stopLocationUpdates() { fusedLocationClient.removeLocationUpdates(mlocationCallback); }

Note : Replace context with your class context and call stopLocationUpdates() inside onDestroy method of your class

Note : For any futher information or doubt you can refer to :

https://developer.android.com/training/location/retrieve-current https://developer.android.com/training/location/change-location-settings https://developer.android.com/training/location/receive-location-updates

You will get your location in Logcat.

Hope this will hope you or somebody else !

like image 21
Aman Kumar Gupta Avatar answered Sep 22 '22 18:09

Aman Kumar Gupta


I believe rather than reinventing the wheel, you can use one of the third party libraries that are easy to implement and in this case, battery efficient. One of the library I found is SmartLocation. You can add the following dependency in your build.gradle (app) to start using the library.

compile 'io.nlopez.smartlocation:library:3.2.9'

After adding the dependency, you should rebuild the project to get the references.

As an example you can try the following code in your Activity.

Button start_btn=(Button)findViewById(R.id.start_location_streaming);

Context context = start_btn.getContext();

Handler handler = new Handler();

start_btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SmartLocation.with(context).location().start(locationListener);
    }
});

OnLocationUpdatedListener locationListener = new OnLocationUpdatedListener({
    @Override
    public void onLocationUpdated(Location location) {
        double lat = location.getLatitude();
        double lng = location.getLongitude();
        handler.postDelayed(locationRunnable,8000);
    }
});

Runnable locationRunnable = new Runnable({
    @Override
    public void run() {
        SmartLocation.with(context).location().start(locationListener);
    }
});

You can stop location tracking in onStop() method

@Override
public void onStop() {
    SmartLocation.with(context).location().stop();
    super.onStop();
}

SmartLocation library will give you more than what is expected, just try that once.

Note: Make sure your application does have ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION (both) to have accurate results. Don't forget to ask for permissions at runtime for Android 6.0 and above.

like image 33
Hitesh Pamnani Avatar answered Sep 18 '22 18:09

Hitesh Pamnani