GPS location not getting updates when app is killed - android

I have a requirement of sending a user's location to a web server after a certain interval, currently sending after every two minutes. It is working fine unless the app is running. When the app is in background location stops getting updated, sending the same location again and again. I am little confused. it would be great if anyone suggests an alternative to my approach. I start location sending on click of a button and does not stop unless and until the user clicks on the button to stop. Below is my code. I want to send current location of the user to a web server whether the app is running or not. Any help is appreciated. problem is not in sending location after a certain interval , problem is location stops getting updated if I kill the app coordinates remain the same. If app is running in foreground then even a slight tilt in device makes the coordinates change. I earlier used firebaseJobDispatcher to call this service. Problem is not in calling the service. Problem is location stops getting updated and remains same every time I call the service if I have killed the app.
I am using alarm manager to call this service every 2 minutes.
public class GPSTracker_DUP extends Service implements LocationListener {
private Context mContext=null;
RetrofitAPI retrofitAPI;
// flag for GPS status
boolean isGPSEnabled = false;
// flag for network status
boolean isNetworkEnabled = false;
// flag for GPS status
boolean canGetLocation = false;
SaveData objSaveData;
Location location; // location
double latitude; // latitude
double longitude; // longitude
private String provider;
// The minimum distance to change Updates in meters
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
// The minimum time between updates in milliseconds
private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1; // 1 minute
// Declaring a Location Manager
protected LocationManager locationManager;
public GPSTracker_DUP(Context context) {
this.mContext = context;
//getLocation();
}
public GPSTracker_DUP(){}
public Location getLocation() {
try {
locationManager = (LocationManager) mContext
.getSystemService(LOCATION_SERVICE);
Criteria criteria = new Criteria();
provider = locationManager.getBestProvider(criteria, false);
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#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 ActivityCompat#requestPermissions for more details.
return null;
}
// getting GPS status
isGPSEnabled = locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
if(!isGPSEnabled)
{
showSettingsAlert();
}
else
{
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,1000*60*2,0,this);
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
Log.e("Provider ", provider + " has been selected."+location.getLatitude()+"==="+location.getLongitude());
saveLocation(location.getLatitude(),location.getLongitude());
//onLocationChanged(location);
}
}
// getting network status
// isNetworkEnabled = locationManager
// .isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch (Exception e) {
e.printStackTrace();
}
return location;
}
public static boolean isConnected(Context context){
NetworkInfo info = getNetworkInfo(context);
return (info != null && info.isConnected());
}
public static NetworkInfo getNetworkInfo(Context context){
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo();
}
/**
* Stop using GPS listener
* Calling this function will stop using GPS in your app
* */
public void stopUsingGPS(){
if(locationManager != null){
locationManager.removeUpdates(GPSTracker_DUP.this);
}
}
/**
* Function to get latitude
* */
public double getLatitude(){
if(location != null){
latitude = location.getLatitude();
}
// return latitude
return latitude;
}
/**
* Function to get longitude
* */
public double getLongitude(){
if(location != null){
longitude = location.getLongitude();
}
// return longitude
return longitude;
}
/**
* Function to check GPS/wifi enabled
* #return boolean
* */
public boolean canGetLocation() {
return this.canGetLocation;
}
/**
* Function to show settings alert dialog
* On pressing Settings button will lauch Settings Options
* */
public void showSettingsAlert(){
AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
// Setting Dialog Title
alertDialog.setTitle("GPS is settings");
// Setting Dialog Message
alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu?");
// On pressing Settings button
alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int which) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
mContext.startActivity(intent);
}
});
// on pressing cancel button
alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
// Showing Alert Message
alertDialog.show();
}
#Override
public void onLocationChanged(Location location) {
latitude = location.getLatitude();
longitude = location.getLongitude();
Log.e("onlocation","changed");
}
public void saveLocation(Double latitude,Double longitude){
objSaveData = new SaveData(mContext);
Log.e("Saving Coordinates", latitude + " " + longitude);
AudioDbHelper audioDbHelper= new AudioDbHelper(mContext);
UserCoordinates userCoordinates = new UserCoordinates();
userCoordinates.setLatitude(String.valueOf(latitude));
userCoordinates.setLongitude(String.valueOf(longitude));
userCoordinates.setUploaded("no");
SaveData objSaveData = new SaveData(mContext);
userCoordinates.setUserEmail(objSaveData.getString("LoginId"));
String time = new SimpleDateFormat("hh:mm: aa").format(Calendar.getInstance().getTime());
userCoordinates.setLocationTime(time);
audioDbHelper.addCoordinates(userCoordinates);
}
#Override
public void onDestroy() {
super.onDestroy();
stopUsingGPS();
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}

Since You need to send location after some interval, It's better to use Job Scheduler which starts the service after an interval, fetches the location and makes the API call.
The best is Job Scheduler and is what is recommended by Google, but Android versions limit it's use, Its better to use Evernote Android Job. Depending on the Android version either the JobScheduler, GcmNetworkManager or AlarmManager is used.
You don't have to worry about the service getting killed as now it's the OS's responsibility to start the service
Also about fetching the location, Use Google PLay Location, to fetch location. What it does is it fetches the location from Google Play service in your device which is updated from time to time.
Take a look at this Util class that I use in one of my projects to fetch location from a running service. It is in Kotlin and uses Dagger2, but you will get the idea. It has a callback interface which replies with the current location and address fetched via Google Play Location Service
ServiceLocationUtil.kt

You need to create a Start_Sticky service for this by default its START_STICKY_COMPATIBILITY. Override onStartCommand().
#Override
public int onStartCommand(Intent intent, int flags, int startId){
// Do your Stuff
return START_STICKY;
}
Whereas due to Background Limitations this will not work in latest versions of android. So you probably want to checkout Background Location Limits and Android 8.0 Behavior Changes.
I suggest you to use JobShedular if you need to send location after some interval. There are some available like Evernote android-job , Firebase JobDispatcher.
Also read Intelligent Job-Scheduling.

You should use WorkManager or FirebaseJobDispatcher for background processes. But FirebaseJobDispatcher is not supported from Android Q.
This is my solution using WorkManager for getting location in background
Define this in activity or fragment
private fun startTaskWithWorkManager() {
val constraints: Constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
val locationWorker =
PeriodicWorkRequest.Builder(LocationWorker::class.java, MIN_PERIODIC_INTERVAL_MILLIS, TimeUnit.MILLISECONDS)
.setConstraints(constraints)
.addTag(LOCATION_WORKER_TAG)
.setInputData(createInputData())
.build()
WorkManager.getInstance()
.enqueueUniquePeriodicWork(LOCATION_WORKER_TAG, ExistingPeriodicWorkPolicy.KEEP, locationWorker)
}
After that you should create a class that will extends from ListenableWorker. In my case I should have to use ListenableWorker instead of Worker. The difference you can find here and here.
class LocationWorker(context: Context, private val workerParams: WorkerParameters) :
ListenableWorker(context, workerParams) {
lateinit var mFuture: SettableFuture<ListenableWorker.Result>
private var fusedLocationProviderClient = FusedLocationProviderClient(context)
#SuppressLint("RestrictedApi", "MissingPermission")
override fun startWork(): ListenableFuture<Result> {
val uniqueId = workerParams.inputData.getString(UNIQUE_ID_KEY)
mFuture = SettableFuture.create()
Timber.d("mFutureStart")
fusedLocationProviderClient.lastLocation.addOnSuccessListener { location ->
Timber.d("location == $location")
if (location != null) {
mFuture.set(Result.success())
} else mFuture.set(Result.failure())
}
return mFuture
}
}
Thats it :)
Work like a charm

Related

Get Lat,Long values periodically from a service and update database

My scenario is to get lat and long of the mobile device for every 20sec and put the lat,long values in database using asmx web service.I have written a service which implements location listener and able to get the lat long values from the service
The implementation of the service is as below.My GpsTracker Service.
public class GPSTracker extends Service implements LocationListener {
// Get Class Name
private static String TAG = GPSTracker.class.getName();
private final Context mContext;
// flag for GPS Status
boolean isGPSEnabled = false;
// flag for network status
boolean isNetworkEnabled = false;
// flag for GPS Tracking is enabled
boolean isGPSTrackingEnabled = false;
Location location;
double latitude;
double longitude;
// How many Geocoder should return our GPSTracker
int geocoderMaxResults = 1;
// The minimum distance to change updates in meters
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
// The minimum time between updates in milliseconds
private static final long MIN_TIME_BW_UPDATES = 1000 *20* 1; //5 seconds
// Declaring a Location Manager
protected LocationManager locationManager;
// Store LocationManager.GPS_PROVIDER or LocationManager.NETWORK_PROVIDER information
private String provider_info;
public GPSTracker(Context context) {
this.mContext = context;
getLocation();
}
/**
* Try to get my current location by GPS or Network Provider
*/
public void getLocation() {
try {
locationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);
//getting GPS status
isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
//getting network status
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
// Try to get location if you GPS Service is enabled
if (isGPSEnabled) {
this.isGPSTrackingEnabled = true;
Log.d(TAG, "Application use GPS Service");
/*
* This provider determines location using
* satellites. Depending on conditions, this provider may take a while to return
* a location fix.
*/
provider_info = LocationManager.GPS_PROVIDER;
} else if (isNetworkEnabled) { // Try to get location if you Network Service is enabled
this.isGPSTrackingEnabled = true;
Log.d(TAG, "Application use Network State to get GPS coordinates");
/*
* This provider determines location based on
* availability of cell tower and WiFi access points. Results are retrieved
* by means of a network lookup.
*/
provider_info = LocationManager.NETWORK_PROVIDER;
}
// Application can use GPS or Network Provider
if (!provider_info.isEmpty()) {
locationManager.requestLocationUpdates(
provider_info,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES,
this
);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(provider_info);
updateGPSCoordinates();
}
}
}
catch (Exception e)
{
//e.printStackTrace();
Log.e(TAG, "Impossible to connect to LocationManager", e);
}
}
/**
* Update GPSTracker latitude and longitude
*/
public void updateGPSCoordinates() {
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
/**
* GPSTracker latitude getter and setter
* #return latitude
*/
public double getLatitude() {
if (location != null) {
latitude = location.getLatitude();
}
return latitude;
}
/**
* GPSTracker longitude getter and setter
* #return
*/
public double getLongitude() {
if (location != null) {
longitude = location.getLongitude();
}
return longitude;
}
/**
* GPSTracker isGPSTrackingEnabled getter.
* Check GPS/wifi is enabled
*/
public boolean getIsGPSTrackingEnabled() {
return this.isGPSTrackingEnabled;
}
/**
* Stop using GPS listener
* Calling this method will stop using GPS in your app
*/
public void stopUsingGPS() {
if (locationManager != null) {
locationManager.removeUpdates(GPSTracker.this);
}
}
#Override
public void onLocationChanged(Location location) {
latitude=location.getLatitude();
longitude=location.getLongitude();
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
And in my activity I have two buttons upon click of the button this service should be started.But now I am having the following problems
1)If the phone goes to sleep mode the lat,long values are not fetched by the service.
2)How to return the lat,long values to the activity so that I can call a web service which puts the lat,long values in database(a different app picks these values from here)
3)The LocationManager.requestlocationupdates function gives lat long values in irregular intervals than what is specified in the arguments
I have seen people using AlarmManager,but i don't get the proper usage as LocationManager.requestlocationupdates provides the same functionality.Connecting to asmx part is pretty clear and I am using ksoap jar file for that.Is there any other which is better than that.
I have also tried using CWAC LocationPoller which is an awesome thing,but as Commonware suggested in previous posts that LocationPoller is designed for much longer polling periods: an hour, not 10 seconds.I have dropped on proceeding that idea.
This is my first Service that I have seen and I am complete newbie to android world who has delved into it 3 days ago.Please Help!!.Expecting your valuable suggestions
Thanks in Advance..

Not getting updates from NETWORK_PROVIDER

I am creating a simple location app that stores the user's location upon command. I am attempting to use both the GPS provider and Network provider to establish the user's location.
The process is achieved using Asynctask and works likes this:
Checks last known GPS location and Network location. If locations are within acceptable parameters the thread finishes.
If last know locations are unacceptable, updates are requested of both GPS and Network.
Once 4 network locations have been found or either 3 gps locations have been found the thread finishes.
A dialog box is displayed when waiting for a location fix.
PROBLEM: GPS seems to be updating whereas Network does not. I have tried solely updating NETWORK_PROVIDER, waited for over an hour with no results. I have tried with both WIFI on and off.
The code for the GetGPS class:
public class GetGPS extends AsyncTask<String, Void, String> implements LocationListener {
private ProgressDialog progDialog;
public double[] DataArray = {0.0,0.0,0.0};
private Integer NetworkCount = 0;
private Integer GPSCount = 0;
private LocationManager mlocManager;
private Context mContext;
private Activity mActivity;
final LocationListener locationListener = (LocationListener) this;
private boolean HasCompleted = false;
public GetGPS(Context context, Activity activity) {
mContext = context;
mActivity = activity;
}
#Override
public void onPreExecute() {
Log.v(getClass().getName(),"PreExecute");
mlocManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
//Stop any current GPS updates
mlocManager.removeUpdates((LocationListener) this);
//Get current system time in millis
long currentTime = System.currentTimeMillis();
//Check last known GPS location and corresponding accuracy and time
String GPSlocationProvider = LocationManager.GPS_PROVIDER;
Location lastKnownGPSLocation = mlocManager.getLastKnownLocation(GPSlocationProvider);
if (lastKnownGPSLocation != null) {
long lastGPStime = lastKnownGPSLocation.getTime();
long timeDifference = currentTime - lastGPStime;
float lastGPSaccuracy = lastKnownGPSLocation.getAccuracy();
Log.v(getClass().getName(),"Found last known GPS! GPS time diff:"+timeDifference+", Accuracy:"+lastGPSaccuracy);
if ((lastGPSaccuracy < 50) && (timeDifference < 180000)) {
Log.v(getClass().getName(),"Acceptable last known GPS location!");
DataArray[0] = (double) lastKnownGPSLocation.getLatitude();
DataArray[1] = (double) lastKnownGPSLocation.getLongitude();
DataArray[2] = (double) lastKnownGPSLocation.getAccuracy();
HasCompleted = true;
}
else {
Log.v(getClass().getName(),"Last known location GPS too inaccurate!");
}
}
else {
Log.v(getClass().getName(),"No previous GPS locations!");
}
//Check last known network location and corresponding accuracy and time
String NetworklocationProvider = LocationManager.NETWORK_PROVIDER;
Location lastKnownNetworkLocation = mlocManager.getLastKnownLocation(NetworklocationProvider);
if (lastKnownNetworkLocation != null) {
long lastNetworktime = lastKnownNetworkLocation.getTime();
long timeDifference = currentTime - lastNetworktime;
float lastNetworkaccuracy = lastKnownNetworkLocation.getAccuracy();
Log.v(getClass().getName(),"Found last known Network location! Time diff:"+timeDifference+", Accuracy:"+lastNetworkaccuracy);
if ((lastNetworkaccuracy < 50) && (timeDifference < 180000)) {
Log.v(getClass().getName(),"Acceptable last known Network location!");
DataArray[0] = (double) lastKnownNetworkLocation.getLatitude();
DataArray[1] = (double) lastKnownNetworkLocation.getLongitude();
DataArray[2] = (double) lastKnownNetworkLocation.getAccuracy();
HasCompleted = true;
}
else {
Log.v(getClass().getName(),"Last known Network location too inaccurate!");
}
}
else {
Log.v(getClass().getName(),"No previous Network locations!");
}
// Request both providers to update
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,(LocationListener) this);
mlocManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0,(LocationListener) this);
//Display dialog box
progDialog = new ProgressDialog(mActivity);
progDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Stop", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Log.v(getClass().getName(),"ProgDialog cancelled");
mlocManager.removeUpdates(locationListener);
GetGPS.this.cancel(true);
}
});
progDialog.setMessage("Acquiring location..");
progDialog.setIndeterminate(true);
progDialog.setCancelable(false);
progDialog.show();
Log.v(getClass().getName(),"Show progdialog");
}
#Override
public String doInBackground(String... params) {
while (HasCompleted == false) {
}
Log.v(getClass().getName(),"doInBackground completed");
return "Success";
}
#Override
public void onPostExecute(String result) {
Log.v(getClass().getName(),"onPostExecute");
//Destroy Dialog box
progDialog.dismiss();
//TODO: Deal with data
}
public void onLocationChanged(Location location) {
Log.v(getClass().getName(),"onLocationChanged, Provider:'"+location.getProvider()+"'");
// Check if from Network
if (location.getProvider().equals("network")){
Log.v(getClass().getName(),"Network location Changed");
NetworkCount = NetworkCount + 1;
if (NetworkCount > 3) {
DataArray[0] = (double) location.getLatitude();
DataArray[1] = (double) location.getLongitude();
DataArray[2] = (double) location.getAccuracy();
Log.v(getClass().getName(),"Location stored from Network!");
Log.v("data array 0","" + DataArray[0]);
mlocManager.removeUpdates((LocationListener) this);
HasCompleted = true;
}
else {
Log.v(getClass().getName(),"Network location count:"+NetworkCount);
}
}
//Check if from GPS
if (location.getProvider().equals("gps")){
Log.v(getClass().getName(),"GPS location Changed");
GPSCount = GPSCount + 1;
if (GPSCount > 2) {
DataArray[0] = (double) location.getLatitude();
DataArray[1] = (double) location.getLongitude();
DataArray[2] = (double) location.getAccuracy();
Log.v(getClass().getName(),"Location stored from GPS!");
//Log.v("data array 0","" + DataArray[0]);
mlocManager.removeUpdates((LocationListener) this);
HasCompleted = true;
}
else {
Log.v(getClass().getName(),"GPS location count:"+GPSCount);
}
}
}
#Override
public void onProviderDisabled(String provider) {
Log.v("OnProviderDisabled", "OnProviderDisabled:"+provider);
}
#Override
public void onProviderEnabled(String provider) {
Log.v("onProviderEnabled", "onProviderEnabled:"+provider);
}
#Override
public void onStatusChanged(String provider, int status,
Bundle extras) {
Log.v("onStatusChanged", "onStatusChanged, provider:"+provider+", Status:"+status);
}
}
The GetGPS class is called in the following manner:
Context mContext = getActivity().getApplicationContext();
Activity mActivity = getActivity();
GetGPS getgps = new GetGPS(mContext, mActivity);
getgps.execute();
Any help as to where i'm going wrong? Thank you in advance forany help.
Also: Is there a simple way to implement a timeout for the Asynctask? I.e. If no location fix is found after a set time period, the thread stops.
About your first question, please check that both GPS and Network providers are enabled at your phone:
I'm also not sure if implementing LocationListener inside AsyncTask is the proper way, I tried to read about it and came across this. Try to read it and implement the solution he propose. (What I would do is create an independent location Singelton class which will have nethods such as stop and start and will be controlled from the AsyncTask).
At your doInBackground method, I would change the While loop, and just put a Thread.sleep(50) inside. to prevent busy waiting.
About your second question, the simplest thing to do here is check the time that has passed in the while loop of doInBackground and stop the thread there is necessary.

How does onLocationChanged works?

in my application i have a button that start counting the time how long the user has been in the same location. and i want the app stop the timer counting if the user goes out from the area he started so i made a class that give me the current location (LAT,LONG,PLACE NAME) and i don't know how to use the "onLocationChanged" and Should I use it? or something else for what i need?
public class MapCurrentPlace extends Service implements LocationListener {
private final Context mContext;
public static final String MY_TEMP = "sharedFile";
SharedPreferences setting;
SharedPreferences.Editor editor;
// flag for GPS status
boolean isGPSEnabled = false;
// flag for network status
boolean isNetworkEnabled = false;
// flag for GPS status
boolean canGetLocation = false;
Location location; // location
double latitude; // latitude
double longitude; // longitude
String placeName = "";
// The minimum distance to change Updates in meters
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 0; // 10 meters
// The minimum time between updates in milliseconds
private static final long MIN_TIME_BW_UPDATES = 500; // 1 minute
// Declaring a Location Manager
protected LocationManager locationManager;
public MapCurrentPlace(Context context) {
this.mContext = context;
getLocation();
}
public String getPlaceName(){
Geocoder gc = new Geocoder(mContext);
try {
List<Address> list = gc.getFromLocation(latitude, longitude, 1);
if(list.size()>0){
String city = list.get(0).getLocality();
String street = list.get(0).getAddressLine(0);
placeName = city+", "+street+"";
}
} catch (IOException e) {
placeName = "";
e.printStackTrace();
}
return placeName;
}
public Location getLocation() {
try {
locationManager = (LocationManager) mContext
.getSystemService(Context.LOCATION_SERVICE);
// getting network status
isNetworkEnabled = locationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
// getting GPS status
isGPSEnabled = locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (!isGPSEnabled) {
// no network provider is enabled
this.canGetLocation = false;
return null;
} else {
this.canGetLocation = true;
if (isNetworkEnabled) {
locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER,MIN_TIME_BW_UPDATES,0, this);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
// if GPS Enabled get lat/long using GPS Services
if (isGPSEnabled) {
if (location == null) {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,MIN_TIME_BW_UPDATES,0, this);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return location;
}
/**
* Stop using GPS listener
* Calling this function will stop using GPS in your app
* */
public void stopUsingGPS(){
if(locationManager != null){
locationManager.removeUpdates(MapCurrentPlace.this);
}
}
/**
* Function to get latitude
* */
public double getLatitude(){
if(location != null){
latitude = location.getLatitude();
}
// return latitude
return latitude;
}
/**
* Function to get longitude
* */
public double getLongitude(){
if(location != null){
longitude = location.getLongitude();
}
// return longitude
return longitude;
}
/**
* Function to check GPS/wifi enabled
* #return boolean
* */
public boolean canGetLocation() {
return this.canGetLocation;
}
public boolean getIsNetworkEnabled() {
return this.isNetworkEnabled;
}
/**
* Function to show settings alert dialog
* On pressing Settings button will lauch Settings Options
* */
public void showSettingsAlert(){
AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
// Setting Dialog Title
alertDialog.setTitle("GPS OFF");
// Setting Dialog Message
alertDialog.setMessage("Allow GPS");
// On pressing Settings button
alertDialog.setPositiveButton("SETTING", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int which) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
mContext.startActivity(intent);
}
});
// on pressing cancel button
alertDialog.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
// Showing Alert Message
alertDialog.show();
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
locationManager.getLastKnownLocation
this one returns last know location fix. This might be kind of old if no apps requested location for a while.
Location updates will be fired each time device location was changed.
So it's up to you what to use. If you want to get up-to date location, use location updates. But bear in mind that location updated drain battery.
Also you might want to look into Geofences: http://developer.android.com/training/location/geofencing.html
The onLocationChanged method will be called when the current location is changed. This is a default method called because you have implemented the LocationListener.
I do not know how you are implementing the timer (perhaps an AsyncTask so your app can do other stuff as well - http://developer.android.com/reference/android/os/AsyncTask.html), but then in the OnLocationChanged method add some call to your timer variable to stop.
OnLocationChanged will trigger whenever the device travels the minDistance parameter of requestLocationUpdates, from the last relevant location of your device (i.e. since the event last triggered).
Of course, the trigger rate also takes into account the minTime parameter, which should be used to prevent saturation of the calls, and thus saving battery/data usage (e.g. car travelling too fast for your minDistance).
As you have it now (you supplied an inline 0 to the call), you need to manually check if the most recent OnLocationChanged data is a relevant change to your scenario.
It's much more transparent to just use that parameter as the system tries to make it hardware-independent and battery-efficient. You already have a MIN_DISTANCE_CHANGE_FOR_UPDATES in your boilerplate code, just add it as a parameter instead of '0' as you have, and set it to the number of meters you need:
// The minimum distance to change Updates in meters
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 30; //30 meters
//...
//at some point while your service/activity is running
locationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES,MIN_DISTANCE_CHANGE_FOR_UPDATES,
this);
//...
#Override
public void onLocationChanged(Location currentLocation) {
//triggered when System asserts a 30 meter variation from last relevant location
doMyStuff();
}
Side note: remember most GPS hardware has issues with very fine locations, especially at sub-10m.
You can also keep the value at 0, receive updates at the granularity the hardware updates itself, and do the checks manually - just use the Location parameter supplied with the event and do your own checks to decide, which is pretty much a geo-fencing check:
Location lastRelevantLocation;
#Override
public void onLocationChanged(Location currentLocation) {
// called when the listener is notified with a location update from the GPS
// hardware update rate might call this more than your CPU should handle
if(checkOutsidePerimeter(location)){
lastRelevantLocation = currentLocation;
doMyStuff();
}
}
Remember minTime if you want to keep tabs on granularity.

Unable to get current location from LocationListener

I have a LocationService which starts onResume() of the MainActivity and stops onDestroy().
#Override
protected void onResume() {
super.onResume();
//Start the service using alaram manager
//If its not running currently
if (isLocationServiceRunning(this)) {
am = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent intent = new Intent(this, LocationService.class);
pi = PendingIntent.getService(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pi);
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(), 1 * 60 * 1000, pi);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if (isLocationServiceRunning(this)) {
stopService(new Intent(this, LocationService.class));
if (am != null && pi != null) {
am.cancel(pi);
}
}
}
LocationService.java
public class LocationService extends Service implements LocationListener {
public static double curLat = 0.0;
public static double curLng = 0.0;
private LocationManager mgr;
private String best;
private Location location;
private Location currentBestLocation;
private static final int TWO_MINUTES = 1000 * 60 * 2;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mgr = (LocationManager) getSystemService(LOCATION_SERVICE);
boolean gps_enabled = mgr
.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (gps_enabled) {
// If GPS is enabled, set criteria as ACCURACY_FINE
// and get the best provider(which usually will be GPS_PROVIDER)
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
best = mgr.getBestProvider(criteria, true);
// getLastKnownLocation so that user don't need to wait
location = mgr.getLastKnownLocation(best);
if (location == null) {
// request for a single update, and try again.
// Later will request for updates every 10 mins
mgr.requestSingleUpdate(criteria, this, null);
location = mgr
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
}
if (location != null) {
// If the GPS gives a location, update curLat and curLng
dumpLocation(location);
} else {
// If the location is still null, go for NETWORK_PROVIDER
best = LocationManager.NETWORK_PROVIDER;
location = mgr.getLastKnownLocation(best);
if (location != null) {
// If the NETWORK gives a location, update curLat and curLng
dumpLocation(location);
}
}
// Register the Location Manager for updates, with both the
// providers
// Since GPS updates are expensive, we ask update every 10 mins and
// unregister updates if GPS is disabled in onProviderDisabled
// callback
mgr.requestLocationUpdates(LocationManager.GPS_PROVIDER,
10 * 60 * 1000, 50, this);
// NETWORK_PROVIDER updates every 20 secs
mgr.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
20 * 1000, 0, this);
return START_NOT_STICKY;
} else {
// If GPS is disables, go with NETWORK_PROVIDER
best = LocationManager.NETWORK_PROVIDER;
location = mgr.getLastKnownLocation(best);
if (location != null) {
dumpLocation(location);
}
// Register NETWORK_PROVIDER for updates every 20 secs
mgr.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
20 * 1000, 0, this);
return START_NOT_STICKY;
}
}
private void dumpLocation(Location l) {
// Called to update the curLat and curLng.
currentBestLocation = l;
SimpleDateFormat s = new SimpleDateFormat("dd/MM/yyyy:hh:mm:ss",
Locale.ENGLISH);
String format = s.format(l.getTime());
try {
Geocoder coder = new Geocoder(this);
List<Address> address;
Address location = null;
address = coder.getFromLocation(l.getLatitude(), l.getLongitude(),
1);
location = address.get(0);
} catch (Exception e) {
Log.e("Exception while getting address", e.getMessage() + "");
}
curLat = l.getLatitude();
curLng = l.getLongitude();
}
#Override
public void onLocationChanged(Location location) {
// called when location is changed, since we registered Location
// Providers
// for updates
if (isBetterLocation(location, currentBestLocation)) {
dumpLocation(location);
} else {
Log.d("Not a Better Location", "Ignore");
}
}
#Override
public void onProviderDisabled(String provider) {
// Check if best(the currently being used provider) is not null
if (best != null) {
// if best and disabled provider are same, the remove updates
if ((provider.equalsIgnoreCase(LocationManager.GPS_PROVIDER) && best
.equals(LocationManager.GPS_PROVIDER))
|| provider
.equalsIgnoreCase(LocationManager.NETWORK_PROVIDER)
&& best.equals(LocationManager.NETWORK_PROVIDER)) {
if (mgr != null) {
mgr.removeUpdates(this);
}
}
}
}
#Override
public void onProviderEnabled(String provider) {
// This will be taken care in the onStartCommand where if gps_enabled
// case is used.
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// No need to care about, because any thing like OUT_OF_SERVICE occurs,
// location being fetched will be null and such cases are handled above.
if ((provider.equals(LocationManager.GPS_PROVIDER))
&& (LocationProvider.OUT_OF_SERVICE == status)) {
if (mgr != null) {
mgr.removeUpdates(this);
}
}
}
#Override
public void onDestroy() {
super.onDestroy();
// triggered when we call stopService(LocationService);
// which is done in onDestroy of MainActivity
// Because LocationService must be stopped
// when application is closed to avoid data usage
if (mgr != null) {
mgr.removeUpdates(this);
}
}
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());
// Not significantly newer or older, so check for Accuracy
if (isMoreAccurate) {
// If more accurate return true
return true;
} else if (isNewer && !isLessAccurate) {
// Same accuracy but newer, return true
return true;
} else if (isNewer && !isSignificantlyLessAccurate
&& isFromSameProvider) {
// Accuracy is less (not much though) but is new, so if from same
// provider return true
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);
}
}
The service surely starts and stops as expected and I can see the location details in log, which are fine.
The problem if when I move to a complete different location(300 miles), the curLat and curLng values still remain as that of the old, when I open the application.
Is it because I am not running the service when the device is in motion(because my application is not running)?
Because when I open some other application like FourSquare(which gets the correct location) and then reopen my application, then it shows the correct location.
What else should I do to refresh the location properly.
I think your problem is here
best = mgr.getBestProvider(criteria, true);
// getLastKnownLocation so that user don't need to wait
location = mgr.getLastKnownLocation(best);
if (location == null) {
// request for a single update, and try again.
// Later will request for updates every 10 mins
mgr.requestSingleUpdate(criteria, this, null);
location = mgr
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
}
because there was previously a location location = mgr.getLastKnownLocation(best); returns that location without starting the provider (see the android documentation. So the location is not null and mgr.requestSingleUpdate(criteria, this, null); is never run.
To get up to date location data a provider must be started.
so a correction could be:
best = mgr.getBestProvider(criteria, true);
// getLastKnownLocation so that user don't need to wait
mgr.requestSingleUpdate(best, this, null);
location = mgr.getLastKnownLocation(best);
Also I'm not sure if it is intended but this service will use the network provider even when GPS data is available and more accurate (due to the 10 minute and 2 minute times chosen for GPS updates and data obsolescence.
P.S. Is there a specific reason you do not want to use FusedLocationProvider that is part of Google Play Services? I have found it to be simpler and it is supposedly optimized for selected best providers and conserving battery.
You code looks perfectly fine if you want to get the location in the foreground. I have gone through in the deep and get to know that in the onDestroy you have stopped the service and alarms also. hence as and when the current app is going to background and the onDestroy is called by system then the code fails to update the location in the background. more over when you launch the application again it will start the service and very first time get the older location which was cached.
when other application updates the location you will get that location according to documentation of the mgr.getLastKnownLocation(best).
Hence to solve this problem do not use alarm here to start service in repeating manner or destory it.
simply start the service and in the onStartCommand ask for the update of the location. and if you want to get rid of the location updates, use removeLocationUpdates(LocationListener) .
Examples are given here http://developer.android.com/training/location/receive-location-updates.html
My best guess is dump "isBetterLocation" and try without it to see what will happen. Based on those checks (which are rather complicated), I think the mistake is either in "isSignificantlyOlder" or in the last return statement (otherwise you would get the new location, correct?)
Have you debugged it to check if the current logic is correct, and if it is, for what distances?
Here is an example to receive location update using Google Play Services
This is MyActivity class
public class MyActivity extends Activity implements
ConnectionCallbacks, OnConnectionFailedListener {
public static final int PLAY_SERVICES_NOT_AVAILABLE_REQUEST = 9000;
public static final int CONNECTION_FAILED_REQUEST = 1000;
private LocationClient mLocationClient;
private LocationRequest mLocationrequest;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_myactivity);
LocationManager mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
mLocationClient = new LocationClient(this, this, this);
boolean isGPSEnabled = mLocationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean isNetworkEnabled = mLocationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
Toast.makeText(this, "GPS: " + isGPSEnabled, Toast.LENGTH_SHORT).show();
Toast.makeText(this, "Network: " + isNetworkEnabled, Toast.LENGTH_SHORT)
.show();
if (isGooglePlayServicesAvailable()) {
mLocationClient.connect();
} else {
// play services not available
}
}
private void defineLocationRequest() {
mLocationrequest = new LocationRequest();
mLocationrequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(5000);
}
private PendingIntent getCallBackIntent() {
return PendingIntent
.getService(getApplicationContext(), 0, new Intent(this,
MyIntentService.class),
PendingIntent.FLAG_UPDATE_CURRENT);
}
private boolean isGooglePlayServicesAvailable() {
int resultCode = GooglePlayServicesUtil
.isGooglePlayServicesAvailable(this);
if (resultCode == ConnectionResult.SUCCESS) {
Log.d("Car Tracking", "play services available.");
return true;
} else {
Log.d("Car Tracking", "play services not available(resultCode:) "
+ resultCode);
GooglePlayServicesUtil.getErrorDialog(resultCode, this,
PLAY_SERVICES_NOT_AVAILABLE_REQUEST).show();
return false;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
switch (requestCode) {
case PLAY_SERVICES_NOT_AVAILABLE_REQUEST:
if (resultCode == Activity.RESULT_OK) {
// check again
}
break;
case CONNECTION_FAILED_REQUEST:
if (resultCode == Activity.RESULT_OK) {
// try to connect LocationClient Againg
}
break;
}
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
// TODO Auto-generated method stub
if (arg0.hasResolution()) {
try {
arg0.startResolutionForResult(this, CONNECTION_FAILED_REQUEST);
} catch (SendIntentException e) {
Log.d("TAG",
"Exception in resolving connection failed: "
+ e.toString());
}
}
}
#Override
public void onConnected(Bundle arg0) {
// TODO Auto-generated method stub
defineLocationRequest();
mLocationClient.requestLocationUpdates(mLocationrequest,
getCallBackIntent());
}
#Override
public void onDisconnected() {
// TODO Auto-generated method stub
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
mLocationClient.removeLocationUpdates(getCallBackIntent());
super.onDestroy();
}
}
Now, this is MyIntentService Class's onHandleIntent Method.
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
if (intent != null) {
Bundle extra = intent.getExtras();
Location location = (Location) extra
.get(LocationClient.KEY_LOCATION_CHANGED);
}
Here, the location object will give you most recent location update
Also add
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
in your manifest
You can use the LocationClient from Google Play Services, its easy to use and proven very efficient.
Here is the link to example
Use Fused Location Provider (new feature available since 4.2 - https://developer.android.com/google/play-services/location.html) - it just gets fast current location and sending updates.
Example: http://www.motta-droid.com/2013/11/location-requests-for-your-app-how-to.html
Just run singleton above in a Service and adjust location update params to your needs.
The only issue You should care about - if it can't determine your current location at all. For example, if just GPS location provider available to your device and you're indoors.
I observed your code..You are updating the location but you are not receiving the updated location information. here is the code how to get the location from a Service
// Send an Intent with an action named "custom-event-name". The Intent sent
// should
// be received by the ReceiverActivity.
private static void sendMessageToActivity(Location l, String msg) {
Intent intent = new Intent("GPSLocationUpdates");
// You can also include some extra data.
intent.putExtra("Status", msg);
Bundle b = new Bundle();
b.putParcelable("Location", l);
intent.putExtra("Location", b);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}
in you main activity or which has to receive the location Info write this code.
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
mMessageReceiver, new IntentFilter("GPSLocationUpdates"));
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle b = intent.getBundleExtra("Location");
lastKnownLoc = (Location) b.getParcelable("Location");
if (lastKnownLoc != null) {
tvLatitude.setText(String.valueOf(lastKnownLoc.getLatitude()));
tvLongitude
.setText(String.valueOf(lastKnownLoc.getLongitude()));
}
}
};
I hope this will work...
I you do not mind waiting for GPS to achieve a first-fix this might help you. The first-fix should only be a matter of seconds if a fix have been found recently.
I have implemented some code that sends callback as soon as there is a first-fix and on locationchange based on GPSTracker from http://www.androidhive.info/2012/07/android-gps-location-manager-tutorial/.
With this implementation you can do:
private GPSTracker gps;
private FirstFixListener firstFixListener;
private LocationUpdateListener locationUpdateListener;
private void startGPS() {
gps = GPSTracker.getInstance(context);
// create listeners
firstFixListener = new MyFirstFixListener();
locationUpdateListener = new MyLocationUpdateListener();
// start the gps
gps.startUsingGPS(firstFixListener, locationUpdateListener);
}
private void stopGPS() {
// stop the gps and unregister callbacks
gps.stopUsingGPS(firstFixListener, locationUpdateListener);
}
private class MyFirstFixListener implements FirstFixListener {
#Override
public void onFirsFixChanged(boolean hasGPSfix) {
if (hasGPSfix == true) {
// accurate position
Location position = gps.getLocation();
}
}
}
private class MyLocationUpdateListener implements LocationUpdateListener {
#Override
public void onLocationChanged(Location location) {
// hand you each new location from the GPS
// you do not need this if you only want to get a single position
}
}
And here is my implementation of GPSTracker:
public class GPSTracker extends Service implements LocationListener {
private static final String TAG = "GPSTracker";
/**
* Register to receive callback on first fix status
*
* #author Morten
*
*/
public interface FirstFixListener {
/**
* Is called whenever gps register a change in first-fix availability
* This is valuable to prevent sending invalid locations to the server.
*
* #param hasGPSfix
*/
public void onFirsFixChanged(boolean hasGPSfix);
}
/**
* Register to receive all location updates
*
* #author Morten
*
*/
public interface LocationUpdateListener {
/**
* Is called every single time the GPS unit register a new location
* The location param will never be null, however, it can be outdated if hasGPSfix is not true.
*
* #param location
*/
public void onLocationChanged(Location location);
}
private Context mContext;
// flag for GPS status
private List<FirstFixListener> firstFixListeners;
private List<LocationUpdateListener> locationUpdateListeners;
boolean isGPSFix = false;
boolean isGPSEnabled = false;
private GPSFixListener gpsListener;
// flag for GPS status
boolean canGetLocation = false;
Location location; // location
double latitude; // latitude
double longitude; // longitude
long mLastLocationMillis;
private boolean logLocationChanges;
// Declaring a Location Manager
protected LocationManager locationManager;
/** removed again as we need multiple instances with different callbacks **/
private static GPSTracker instance;
public static GPSTracker getInstance(Context context) {
if (instance != null) {
return instance;
}
return instance = new GPSTracker(context);
}
private GPSTracker(Context context) {
this.mContext = context;
gpsListener = new GPSFixListener();
firstFixListeners = new ArrayList<GPSTracker.FirstFixListener>();
locationUpdateListeners = new ArrayList<GPSTracker.LocationUpdateListener>();
}
public boolean hasGPSFirstFix() {
return isGPSFix;
}
private void addFirstFixListener(FirstFixListener firstFixListener) {
this.firstFixListeners.add(firstFixListener);
}
private void addLocationUpdateListener(
LocationUpdateListener locationUpdateListener) {
this.locationUpdateListeners.add(locationUpdateListener);
}
private void removeFirstFixListener(FirstFixListener firstFixListener) {
this.firstFixListeners.remove(firstFixListener);
}
private void removeLocationUpdateListener(
LocationUpdateListener locationUpdateListener) {
this.locationUpdateListeners.remove(locationUpdateListener);
}
public void setLogLocationChanges(boolean logLocationChanges) {
this.logLocationChanges = logLocationChanges;
}
public Location getLocation() {
return location;
}
private Location startLocationListener() {
canGetLocation = false;
try {
locationManager = (LocationManager) mContext
.getSystemService(Service.LOCATION_SERVICE);
// getting GPS status
isGPSEnabled = locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (isGPSEnabled) {
if (location == null) {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 0, 0, this);
locationManager.addGpsStatusListener(gpsListener);
if (locationManager != null) {
location = locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
}
}
}
} else {
showSettingsAlert();
}
} catch (Exception e) {
e.printStackTrace();
}
return location;
}
public void stopUsingGPS(FirstFixListener firstFixListener,
LocationUpdateListener locationUpdateListener) {
if (firstFixListener != null)
removeFirstFixListener(firstFixListener);
if (locationUpdateListener != null)
removeLocationUpdateListener(locationUpdateListener);
stopUsingGPS();
}
/**
* Stop using GPS listener Calling this function will stop using GPS in your
* app
* */
public void stopUsingGPS() {
Log.d("DEBUG", "GPS stop");
if (locationManager != null) {
locationManager.removeUpdates(GPSTracker.this);
location = null;
if (gpsListener != null) {
locationManager.removeGpsStatusListener(gpsListener);
}
}
isGPSFix = false;
location = null;
}
public void startUsingGPS(FirstFixListener firstFixListener,
LocationUpdateListener locationUpdateListener) {
Log.d("DEBUG", "GPS start");
if (firstFixListener != null)
addFirstFixListener(firstFixListener);
if (locationUpdateListener != null)
addLocationUpdateListener(locationUpdateListener);
startLocationListener();
}
/**
* Function to get latitude
* */
public double getLatitude() {
if (location != null) {
latitude = location.getLatitude();
} else {
Log.e("GPSTracker", "getLatitude location is null");
}
// return latitude
return latitude;
}
/**
* Function to get longitude
* */
public double getLongitude() {
if (location != null) {
longitude = location.getLongitude();
} else {
Log.e("GPSTracker", "getLongitude location is null");
}
// return longitude
return longitude;
}
/**
* Function to check GPS/wifi enabled
*
* #return boolean
* */
public boolean canGetLocation() {
return this.canGetLocation;
}
/**
* Function to show settings alert dialog On pressing Settings button will
* lauch Settings Options
* */
public void showSettingsAlert() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
// Setting Dialog Title
alertDialog.setTitle("GPS settings");
// Setting Dialog Message
alertDialog
.setMessage("GPS is not enabled. Do you want to go to settings menu?");
// On pressing Settings button
alertDialog.setPositiveButton("Settings",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(
Settings.ACTION_LOCATION_SOURCE_SETTINGS);
mContext.startActivity(intent);
}
});
// on pressing cancel button
alertDialog.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
// Showing Alert Message
alertDialog.show();
}
#Override
public void onLocationChanged(Location location) {
if ( location == null)
return;
this.location = location;
mLastLocationMillis = SystemClock.elapsedRealtime();
canGetLocation = true;
if (isGPSFix) {
if (locationUpdateListeners != null) {
for (LocationUpdateListener listener : locationUpdateListeners) {
listener.onLocationChanged(location);
}
}
}
}
#Override
public void onProviderDisabled(String provider) {
canGetLocation = false;
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
private boolean wasGPSFix = false;
// http://stackoverflow.com/questions/2021176/how-can-i-check-the-current-status-of-the-gps-receiver
// answer from soundmaven
private class GPSFixListener implements GpsStatus.Listener {
public void onGpsStatusChanged(int event) {
switch (event) {
case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
isGPSFix = (SystemClock.elapsedRealtime() - mLastLocationMillis) < 3000;
if (isGPSFix != wasGPSFix) { // only notify on changes
wasGPSFix = isGPSFix;
for (FirstFixListener listener : firstFixListeners) {
listener.onFirsFixChanged(isGPSFix);
}
}
break;
case GpsStatus.GPS_EVENT_FIRST_FIX:
// Do something.
break;
}
}
}
}

Android locationManager requestLocationUpdates doesn't work

I am developing an application which lists restaurants closest to the user. When the refresh button is clicked, it lists the restaurants for the user's current location. I am using the Location Manager and requesting updates only when the activity comes to foreground(onResume) to avoid the constant usage of the battery. When the app goes in onPause(), the location updates are stopped. It works fine on the emulator when I pass the updates through the terminal.
Problem:
When I physically change my location (say drive 5 miles away) and I open my app and the activity to show the nearest restaurants, it takes long time(4-5 minutes) for the location to refresh and till then the app continues to show the restaurants for the previous location. But if I physically change my location and access Google Maps and then open my restaurant application, then it works instantaneously. I have ensured that the GPS is switched on. What can I do to get the Location Manager to kick in and refresh the location as soon as I open my activity?
Thank you in advance!
package com.mortley.android.restaurantsaver;
public class NearbyRestaurantActivity extends ListActivity implements OnClickListener, LocationListener{
private Button refreshButton, searchRestaurants;
ImageButton goToSearch;
private double[] lastKnownLocation;
private EditText locationEditText;
private LocationManager locManager;
private LocationListener locListener;
private boolean gps_enabled = false;
private boolean network_enabled = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.nearbyrestaurants);
refreshButton = (Button)findViewById(R.id.reloadButton);
refreshButton.setOnClickListener(this);
searchRestaurants = (Button)findViewById(R.id.searchButton);
searchRestaurants.setOnClickListener(this);
goToSearch = (ImageButton)findViewById(R.id.goLocationButton);
goToSearch.setOnClickListener(this);
locationEditText = (EditText)findViewById(R.id.addressTextBox);
locationEditText.setVisibility(View.GONE);
goToSearch.setVisibility(View.GONE);
locManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);//??
locManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 1000, 100, this);
//checks network connectivity
boolean checkConnection = isNetworkAvailable();
if(!checkConnection){
Toast.makeText(getApplicationContext(), "Check your Network Connectivity", Toast.LENGTH_LONG).show();
}
if(checkConnection){
//sets current location parameters for the user
lastKnownLocation = RestaurantHelper.getLastKnownLocation(this);
//Log.v("NearbyRestaurantActivity", "This"+this);
RestaurantApplication application = (RestaurantApplication) this.getApplication();
RestaurantAdapter restaurantAdapter = new RestaurantAdapter(this, R.layout.restaurantrow, R.id.label,new ArrayList<RestaurantReference>());
restaurantAdapter.setLastKnownLocation(lastKnownLocation);
//set a global variable for the RestaurantAdapter in the RestaurantApplication class.
application.setRestaurantAdapter(restaurantAdapter);
//Set the adapter first and then update it when the RestaurantHttpAsyncTask makes a web service call.
setListAdapter(restaurantAdapter);
//Make a webservice call in a different thread passing Keyword for URL as a string array.
RestaurantHttpAsyncTask m_progressTask;
String[] keywords = {"", "american", "asian", "italian","mexican"};
//String[] keywords = {"indian"};
m_progressTask = new RestaurantHttpAsyncTask(NearbyRestaurantActivity.this, keywords);
m_progressTask.setRestaurantAdapter(restaurantAdapter);
m_progressTask.execute();
}
}
#Override
public void onClick(View v) {
//Refresh button helps to refresh the restaurant list on location change. Again it makes a call to the webservice using Async Task
if(v.getId() == refreshButton.getId() ){
try {
gps_enabled = locManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
} catch (Exception ex) {
ex.printStackTrace();
}
try {
network_enabled = locManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch (Exception ex) {
ex.printStackTrace();
}
// don't start listeners if no provider is enabled
if (!gps_enabled && !network_enabled) {
Toast.makeText(getApplicationContext(), "Sorry, Location is not determined. Please enable your Network Providers.", Toast.LENGTH_LONG).show();
}
//check network connectivity before refresh
boolean checkConnection = isNetworkAvailable();
if(!checkConnection){
Toast.makeText(getApplicationContext(), "Check your Network Connectivity", Toast.LENGTH_LONG).show();
}
if(checkConnection){
RestaurantApplication application = (RestaurantApplication) this.getApplication();
RestaurantAdapter restaurantAdapter = new RestaurantAdapter(this, R.layout.restaurantrow, R.id.label, new ArrayList<RestaurantReference>());
restaurantAdapter.setLastKnownLocation(lastKnownLocation);
//set a global variable for the RestaurantAdapter in the RestaurantApplication class.
application.setRestaurantAdapter(restaurantAdapter);
//Set the adapter first and then update it when the RestaurantHttpAsyncTask makes a web service call.
setListAdapter(restaurantAdapter);
//Make a webservice call in a different thread passing Keyword for URL as a string array.
RestaurantHttpAsyncTask m_progressTask, m_progressTask1;
String[] keywords = {"", "american", "asian", "italian","mexican", "chinese", "indian"};
//String[] keywords = {"Chinese"};
m_progressTask = new RestaurantHttpAsyncTask(NearbyRestaurantActivity.this, keywords);
m_progressTask.setRestaurantAdapter(restaurantAdapter);
m_progressTask.execute();
}
}
if(v.getId() == goToSearch.getId() ){
Activity child = this;
while(child.getParent() != null){
child = child.getParent();
}
TabGroup1Activity parent = (TabGroup1Activity)getParent();
InputMethodManager imm = (InputMethodManager)getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(locationEditText.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
//changes ** restaurantAdapter to RestaurantAdapter1 to test & application to application1
RestaurantApplication application1 = (RestaurantApplication) this.getApplication();
RestaurantAdapter restaurantAdapter1 = new RestaurantAdapter(this, R.layout.restaurantrow, R.id.label, new ArrayList<RestaurantReference>());
restaurantAdapter1.setLastKnownLocation(lastKnownLocation);
//set a global variable for the RestaurantAdapter in the RestaurantApplication class.
application1.setRestaurantAdapter(restaurantAdapter1);
//Set the adapter first and then update it when the RestaurantHttpAsyncTask makes a web service call.
setListAdapter(restaurantAdapter1);
//Make a webservice call in a different thread passing Keyword for URL as a string array.
RestaurantHttpAsyncTaskTextSearch m_progressTask, m_progressTask1;
String keywords = locationEditText.getText().toString();
if(keywords.equals("")){
keywords = "Pizza in Palo Alto";
}
keywords = keywords.replaceAll(" ", "%20");
keywords = keywords.replaceAll(",", "%20");
m_progressTask = new RestaurantHttpAsyncTaskTextSearch (NearbyRestaurantActivity.this, keywords);
m_progressTask.setRestaurantAdapter(restaurantAdapter1);
m_progressTask.execute();
locationEditText.setVisibility(View.GONE);
goToSearch.setVisibility(View.GONE);
}
if(v.getId() == searchRestaurants.getId() ){
if(goToSearch.isShown() == true){
goToSearch.setVisibility(View.GONE);
locationEditText.setVisibility(View.GONE);
}
else if(goToSearch.isShown() == false){
//check network connectivity before refresh
boolean checkConnection = isNetworkAvailable();
if(!checkConnection){
Toast.makeText(getApplicationContext(), "Check your Network Connectivity", Toast.LENGTH_LONG).show();
}
if(checkConnection){
goToSearch.setVisibility(View.VISIBLE);
locationEditText.setVisibility(View.VISIBLE);
}
}
}
}
//Method to check network connectivity
public boolean isNetworkAvailable() {
ConnectivityManager connectivityManager
= (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting()) {
//Log.d("network", "Network available:true");
return true;
} else {
//Log.d("network", "Network available:false");
return false;
}
}
#Override
protected void onResume() {
super.onResume();
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 50, 100, this);
//Log.v("NearbyRestaurantActivity", "In OnResume()");
}
#Override
protected void onPause() {
super.onPause();
locManager.removeUpdates(this);
//Log.v("NearbyRestaurantActivity", "In onPause()");
}
#Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
}
public class RestaurantHelper {
public static double[] getLastKnownLocation(Activity activity){
double lat = 0.0;
double lon = 0.0;
LocationManager lm = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
Location location = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if(location == null){
lat = 0.0;
lon = 0.0;
}
else{
//Log.v("Latitude", Double.toString(location.getLatitude()));
//Log.v("Longitude", Double.toString(location.getLongitude()));
lat = location.getLatitude();
lon = location.getLongitude();
}
return new double[]{lat,lon};
}
}
The primary reason why you aren't getting updated location information quickly is that you're relying on the NETWORK_PROVIDER in the RestaurantHelper.getLastKnownLocation() method, but registering a LocationListener for the GPS_PROVIDER in onCreate().
So, this code in RestaurantHelper.getLastKnownLocation():
Location location = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
...should be changed to:
Location location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
In theory, this should then give you the latest GPS location, which should have been refreshed when you register the listener. Conversely, you could also change to listening to the NETWORK_PROVIDER in onCreate() and leave RestaurantHelper.getLastKnownLocation() as is. It depends on your accuracy requirement - if you want high accuracy locations to return the nearest location to the nearest building level (e.g., 5-30m), you should use the GPS_PROVIDER. But, if you can live with coarser accuracy, the NETWORK_PROVIDER typically returns a new location much faster than GPS, especially if you're indoors, and sometimes this can be fairly accurate if derived from WiFi.
Another approach would be to listen to both GPS_PROVIDER and NETWORK_PROVIDER by registering both via two requestLocationUpdates() lines in onCreate(), and then checking to see most recent timestamp on the Location from lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); and lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);, and using the one that was updated more recently.
I would also recommend the following changes to make your code reliable on a large number of Android devices:
Specify the requestLocationUpdates() minDistance parameter as 0 when listening for GPS or NETWORK location updates - the minDistance parameter has a history of being unreliable and unpredictable in the way its interpreted by OEMs, until Android 4.1.
Switch to the new Fused Location Provider - this should be much more reliable when calling the getLastKnownLocation() method than the Android framework location APIs, and more consistent across different devices. Note that this relies on Google Play Services SDK, which is only available on Android 2.2 and higher.
I have 2 advice for you
LocationClient video, is the new way of doing location stuff. It has improvements over the LocationManager that can be a pain to manage and develop.
If you need to use LocationManager, you must know that requestLocationUpdates is buggy (very buggy). Since all its implementations on custom hardware differ. There is a hack/workaround that works. Before you call requestLocationUpdates, just kick start it with the following
Code :
HomeScreen.getLocationManager().requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 0, 0, new LocationListener() {
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onLocationChanged(final Location location) {
}
});
requestLocationUpdates is buggy. Use network provider always to trigger onLocationChanged(...)
locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 100, this)
only after using network provider use gps provider back to back:
locManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 1000, 100, this)
do not forget to check if gps is enabled or not before requesting location update by gps.

Categories

Resources