I'm working in a Xamarin project that's going to track users while they are working, even if the app is closed. It's basically an app for our clients (we have an ERP) track their sellers.
For that, I've implemented a pretty simple BroadcastReceiver for starting a service (LocationService) that is going to get user's position and save it in a database or POST to some API.
The problem is that when I'm not using LocationManager, it works fine (I close the app and it keep toasting messages for example). But if I use the LocationManager the service "crash" after the app is closed and stop tracking. Am I doing something wrong? The project is fully configured for GPS tracking (it works fine when app is open or suspended).
PS: That's my first time working with Xamarin.Android. Before I've just worked with Xamarin.Forms.
Here's the LogCat. It seems to happen when AlarmManager is fired and try to get location.
Here's my code:
Start tracking
private void StartTrackingAlarm(int period)
{
Intent intent = new Intent(this, typeof(TrackingService));
PendingIntent pendingIntent = PendingIntent.GetBroadcast(this, 0, intent, PendingIntentFlags.CancelCurrent);
WriteLine($"Started tracking with period of {period} seconds.");
AlarmManager manager = (AlarmManager)GetSystemService(AlarmService);
manager.SetRepeating(AlarmType.RtcWakeup, SystemClock.ElapsedRealtime(), period * 1000, pendingIntent);
}
private void StopTrackingAlarm()
{
Intent intent = new Intent(this, typeof(TrackingService));
PendingIntent pendingIntent = PendingIntent.GetBroadcast(this, 0, intent, 0);
WriteLine($"Stopped tracking at {DateTime.Now.ToLongTimeString()} seconds.");
AlarmManager manager = (AlarmManager)GetSystemService(AlarmService);
manager.Cancel(pendingIntent);
}
BroadcastReceiver
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new string[] { "android.intent.action.BOOT_COMPLETED" }, Priority = (int)IntentFilterPriority.HighPriority)]
public class TrackingService : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Intent intentToStart = new Intent(context, typeof(LocationService));
context.StartService(intentToStart);
}
}
LocationService
[Service]
public class LocationService : IntentService, ILocationListener
{
private string LogTag => $"[{nameof(LocationService)}]";
private LocationManager LocManager { get; set; }
private string LocationProvider { get; set; }
protected override void OnHandleIntent(Intent intent)
{
Log.WriteLine(LogPriority.Debug, LogTag, $"Handling intent at {DateTime.Now.ToLongTimeString()}");
InitializeLocationManager();
if (LocManager.IsProviderEnabled(LocationProvider))
{
LocManager.RequestSingleUpdate(LocationProvider, this, null);
Location location = LocManager.GetLastKnownLocation(LocationProvider);
Log.WriteLine(LogPriority.Debug, LogTag, $"Last Position: [{location.Latitude}, {location.Longitude}].");
}
}
private void InitializeLocationManager()
{
LocManager = (LocationManager)GetSystemService(LocationService);
Criteria criteriaForLocationService = new Criteria { Accuracy = Accuracy.Fine };
IList<string> acceptableLocationProviders = LocManager.GetProviders(criteriaForLocationService, true);
if (acceptableLocationProviders.Any())
LocationProvider = acceptableLocationProviders.First();
else
LocationProvider = string.Empty;
Log.Debug(LogTag, $"Using {LocationProvider} at {DateTime.Now}.");
}
#region ILocationListener
public void OnLocationChanged(Location location) { }
public void OnProviderDisabled(string provider) { }
public void OnProviderEnabled(string provider) { }
public void OnStatusChanged(string provider, [GeneratedEnum] Availability status, Bundle extras) { }
#endregion
}