Send Location Updates to Server in Background - android

What is the best way to keep user's location in sync with server,even after the app is terminated?
here is what I found this far
using a foreground service. I already tested that but it's battery consuming, and sometimes it's killed when you lock the phone or turn off the screen.
using work manager. I also tested it, it sends the location every 15 mins,but so unreliable, and it stopped sending after a while.
Geofencing. I read that Geofencing api gets location updates more often, every couple of minutes or so, but I haven't tested it.
LocationListener. There is a method called onLocationChanged, but I don't know how would it work in background.
is there something like a broadcast receiver that will be fired only when location changed by a margin? I think this would be an optimized solution.
I am building an app that uses a feature similar to facebook nearby friends (which is stopped working long time ago) or something like tinder to display nearby people.
Currently I need this for android, but I will need it for IOS as well, I am developing a flutter app.

I already used a similar method in my app which is working:
I used foreground service to record the location, the battery consumptions are related to the frequency of location request not really the foreground service itself. indeed using LocationListener is a good option
then I am checking the foreground service regularly using workmanager and restart it when needed.
best

As discussed in the comments above, I don't really think Android allows for you to get location updates in the background even when the application is not active.
I recommend you instead try to query for location as soon as the app starts, and quickly follow up with whatever actions you need to make with it. As an option, you can also keep track of location history by caching their location as they interact with the app, in case you want to keep the database as fresh as possible.
Here's some pseudo code as a simple example:
class MainActivity : AppCompatActivity() {
override fun onCreate(..) {
queryForLocation(..)?.let {
doSomething(it)
cacheLocation(it)
} ?: Log.d(TAG, "Location = null")
}
override fun onDestroy() {
queryForLocation(..)?.let {
cacheLocation(it)
} ?: Log.d(TAG, "Location = null")
}

Related

Foreground or Background service to track user's location?

I'm developing a location aware app. This app will start tracking users when they are in their workday. These are the requirements:
The service should run on a regular basis (every 30 or 45 min).
It won't matter if the service does not trigger at the same basis everytime.
The service needs to upload data to our firestore db.
I doesn't need to be triggered on specific conditions (data is on, phone is charging, etc...)
I need this to run even if the user restarts his phone.
We may need to track the distance traveled by the user. (This is not a requirement per se, but it may be a feature someday)
I know there are a lot of ways to achieve this, but I have not decided which is the option that best fits my scenario. This is what I've thought so far:
Foreground service combined with BroadcastReciever in case the phone is rebooted
Background service using the new jetpack's Workmanager.
Which will the best solution? Do you think there is a better solution than those?
Thanks!
Was thinking create a GPS location tracker so when they are in work premise as well as outside it kinda shows.
Then consider adding the number 5 of the above. Like you said there could be mire awesome solutions than these so lets wait for options.

Scanning for beacons and getting location periodically in the foreground

I am using the beacon library to scan for beacons with a foreground service and a persistent notification. I have tested this on both Android 9.0 and 7.0, and the app works as expected, and sends the beacons scanned to a server every 30 seconds. Now, I am trying to add location scanning to the app, so that it retrieves location updates every 30 seconds. I am using the Google Play API, and set up a location request with an interval of 30 secs. Then, I created a FusedLocationProvider client in my application class, so I gave it my app's (not activity's) context. Then, I gave my request and the following callback to the client:
locationCallback = new LocationCallback()
{
#Override
public void onLocationResult(LocationResult locationResult)
{
if ( locationResult != null )
{
Log.d(TAG, "location acquired: " + locationResult.getLastLocation());
beaconContainer.setLocation(locationResult.getLastLocation());
}
}
};
The beaconContainer object holds a list of beacons and the latest location (and a timestap of when the latest location was acquired using LocalTime.now()), and sends these to the server every 30 seconds. At first, the app seems to work and the location timestamp is within 30 seconds of when the request to the server was sent. However, after some time has passed (and the screen has been off for some time), it seems that the onLocationResult method in the callback is not being called and the location is not being updated. For example, the server request was made at 12:34 but the location was updated at 10:21. Note that the beacon scanning is still being correctly performed as expected.
I was wondering if this is because the phone that I tested this on was stationary, or if it is because I did not use a service for location updating. To me, it seems to be the former because my app has a foreground service (ble scanner) and a persistent notification, so according to the docs, it is in the foreground and it should not be subject to background limitations. If it is the latter, how can I fuse the beacon library's foreground service with my location scanning so that they both run as expected.
Thanks.
EDIT:
Here is a screenshot of battery historian, showing how BLE is regularly and consistently being used while GPS is used for intermittent periods.
The documentation for FusedLocationProviderClient indicates that on Android 8+, if the app is not in the foreground, you will only get updates a "few times each hour". See here. This is likely because the implementation inside Google Play Services uses the JobScheduler on Android 8+ to get around background service limits, and jobs are limited to running every 15 minutes +/- 5 minutes in the background. Since Google Play Services APIs are closed source and proprietary, it is difficult to say more about its internal implementation, but it is unlikely that it takes into account that your app has a foreground service. (The Android Beacon Library, by contrast, is explicitly designed to behave differently when configured with a Foreground Service so you get more frequent updates.)
It's unclear how the FusedLocationProviderClient works differently in the background on Android 7. It may not work differently at all, and may follow the pattern described above in the background simply if your app targets SDK 26 or higher. You'd have to test to make sure -- effectively reverse engineering Google Play Services. Even if you do figure it out, the behavior might change in the next Google Play Services version, and you'll never know about it unless you reverse-engineer it again. This is the peril of using closed-source SDKs.
An alternative would be to instead use the open-source location APIs provided by Android.
LocationManager locationManager = (LocationManager)
this.getSystemService(Context.LOCATION_SERVICE);
try {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 400l, (float) 1000.0, this); //You can also use LocationManager.GPS_PROVIDER and LocationManager.PASSIVE_PROVIDER
}
catch (SecurityException e) {
Log.d(TAG, "Can't get location -- permission denied");
}
Of course, you'll want to adjust the accuracy and update interval to suit your needs and conserve battery. And you will certainly find dropouts in callbacks when your phone enters Doze mode. But you should be able to use the above in your Application class as you describe in your question without the annoyingly opaque behaviors added by Google Play Services.

Separate class or Service for FusedLocationProvider Location updates?

I currently have a class named LocationCheck.
public class SpeedCheck {
Here the location is retrieved every 3 seconds and is ongoing until the user stops it. To start checking for locations, the class is called in the Main Activity:
startLoc = new LocationCheck(this);
What i am wondering is if the code needs to be in a Service class rather than just an ordinary class (like it currently is). It works so far with no issues, but i may be misunderstanding the concept of Services etc and could be unaware of problems it may face over checking over a long period of time (fairly new to Android dev).
I have looked into Background Service for location updates, but with FusedLocationProvider (which i am using) it is only possible to receive several updates over an hour. This would not be helpful as i need an update every 3 seconds.
Any advice would be greatly appreciated.
If you need to keep checking location in background then use service else you can just simply use it in activity. Simply stop the service when you no longer need it because it will consume more battery if left running in background.

Periodic foreground location tracking on Android

I am in the process of creating a custom Phonegap plugin for Android that monitors location both when the app is in the foreground and when it is backgrounded. Google documentation on using the FusedLocationProviderAPI is remarkably clear. The process I have worked out thus far is as follows
Ensure that the API is available
GoogleApiAvailability api = GoogleApiAvailability.getInstance();
int code = api.isGooglePlayServicesAvailable(ctxt);
return (code == ConnectionResult.SUCCESS);
Define a LocationListener with assigned callbacks to handle the results retured by the requestLocationUpdates method.
Create a LocationRequest
Here is where things become slightly unclear
setInterval - the interval at which the app wants location updates
setFastestInterval - the interval at which it will consume updates if available.
setSmallestDistance & setPriorty - clear enough
setNumUpdates - how this works is not clear to me. Reading between the lines I am assuming that if I use setInterval(60000) and setNumUpdates(1000) the system will keep sending back location updates for the next 6000 minutes or until such time as the app is backgrounded/shutdown or I/the user cancels location updates.
But then this begs the question - what does the app need to do to be a good citizen. I am assuming that would have to be something like this
Record the PendingResult being returned by the requestLocationUpdates call.
Detect when the onPause event occurs
call PendingResultt.cancel() prior to letting the app go to the background
I'd be much obliged if someone could comment on the correctness of this workflow.
A related issue - The documentation for PendingResult states
It is the responsibility of the caller or callback receiver to release any resources associated with the returned result.
It is not clear to me what resources they are talking about here. The LocationListener.onLocationChanged event returns a Location object which I assume will be garbage collected when it goes out of scope. Presumably the PendingResult being returned by requestLocationUpdates should be canceled and then set to null when the app goes to the background. Is there anything else one needs to do by way of releasing resources?
A few hours later
I created two versions of my test app
App 1:Sets up the LocationRequest with setNumUpdates(10000). Pops up toasts on location change in the form App 1:Location is...
App 2:Sets up the LocationRequest with setNumUpdates(1). Pops up toasts on location change in the form App 2`:Location is...
I had the two apps running simultaneously and simulated position changes with the help of a really neat little app called FakeGPS. Both App1 and App2 provided me with an update when I did my first fake location change. However, all subsequent location changes were reported only by App 1.
By inference then setNumUpdates provides a mechanism for polling for updates periodically. What is slightly confusing is that the updates continue even after the app is backgrounded - though I assume that this is largely because it is at the mercy of the OS which will kill it when it deems fit.
However, all of the above is based on empirical testing. I find surprisingly little on the setNumUpdates setting.
To your question, Is update continue even if app is in background:
Ans: What ever be the case setNumUpdates is 1 or x, when your app is in background and is still registered to update, you will get the updates, unless the OS has killed your app, for memory.
The only difference that setNumUpdates does is, as you said correctly, if its set to 1, it will give only one update, unless you has reregistered again.
Link has sufficient definition for setNumUpdates
https://developers.google.com/android/reference/com/google/android/gms/location/LocationRequest.html#public-methods

Where to initialize GPS to stay on for longer than the activities

I am writing an application that has to send to the server its GPS location every X seconds, and I was wondering if the right place to have this running was inside the Application Class since it has to keep sending messages even if you change activities.
Right now I initialized inside the activity and then have a different thread with a timer send the latest location to the backend.
Am I correct? I ask mainly because I have had complains that the GPS sometimes gets stuck, but when they launch another application with a GPS it starts working again in my program.
[EDIT: the application is for a company that will be using the app alone in a Galaxy Tab]
Thanks
A simple way: Create a Service and register it to listen to LocationManager updates. If you want to send data even when phone goes to sleep then take a look at WAKE LOCK.
However this will use GPS and network and will drain battery. People don't like such apps - I know I wouldn't use it.
To make things more user-friendly:
Use passive location provider. This leeches location data when other apps use Gps. Use Gps directly only when you dont get data for a longer period.
Cache location data. Register with sync manager to update data when other app also update data. Use DownloadManager to upload data files: DM is smart, it automatically retries on error, even if device is restarted. If files are big, then set it to only upload over wifi.
I highly recommend watching Reto Meier's Android Protips video http://www.youtube.com/watch?v=twmuBbC_oB8

Categories

Resources