Task: Create a background task to run when application is stopped/paused that periodically (3-7 seconds) performs HTTP requests and stores response information in mysqlite and displays local notifications when required.
I have create a background service like the following,
[Service(Enabled = true)]
public class MyRequestService : Service
That is started like an intent from MainActivity,
public void StartMyRequestService()
{
var serviceToStart = new Intent(this, typeof(MyRequestService));
StartService(serviceToStart);
}
public void StopMyRequestService()
{
var serviceToStart = new Intent(this, typeof(MyRequestService));
StopService(serviceToStart);
}
protected override void OnPause()
{
base.OnPause();
StartMyRequestService();
}
protected override void OnDestroy()
{
base.OnDestroy();
StartMyRequestService();
}
protected override void OnResume()
{
base.OnResume();
StopMyRequestService();
}
In my service I have the following features in use,
- return STICKY in OnStartCommand
- create a 'permanent' native
- notification with channel
- power manager lock
And the code looks like the following,
private Handler handler;
private Action runnable;
private bool isStarted
private WakeLock wakeLock;
public override void OnCreate()
{
base.OnCreate();
handler = new Handler();
runnable = new Action(() =>
{
DispatchNotificationThatAlarmIsGenerated("I'm running");
handler.PostDelayed(runnable, DELAY_BETWEEN_LOG_MESSAGES);
});
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
if (isStarted)
{
// service is already started
}
else
{
CreateNotificationChannel();
DispatchNotificationThatServiceIsRunning();
handler.PostDelayed(runnable, DELAY_BETWEEN_LOG_MESSAGES);
isStarted = true;
PowerManager powerManager = (PowerManager)this.GetSystemService(Context.PowerService);
WakeLock wakeLock = powerManager.NewWakeLock(WakeLockFlags.Full, "Client Lock");
wakeLock.Acquire();
}
return StartCommandResult.Sticky;
}
public override void OnTaskRemoved(Intent rootIntent)
{
//base.OnTaskRemoved(rootIntent);
}
public override IBinder OnBind(Intent intent)
{
// Return null because this is a pure started service. A hybrid service would return a binder that would
// allow access to the GetFormattedStamp() method.
return null;
}
public override void OnDestroy()
{
// Stop the handler.
handler.RemoveCallbacks(runnable);
// Remove the notification from the status bar.
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Cancel(NOTIFICATION_SERVICE_ID);
isStarted = false;
wakeLock.Release();
base.OnDestroy();
}
private void CreateNotificationChannel()
{
//Notification Channel
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationImportance.Max);
notificationChannel.EnableLights(true);
notificationChannel.LightColor = Color.Red;
notificationChannel.EnableVibration(true);
notificationChannel.SetVibrationPattern(new long[] { 100, 200, 300, 400, 500, 400, 300, 200, 400 });
NotificationManager notificationManager = (NotificationManager)this.GetSystemService(Context.NotificationService);
notificationManager.CreateNotificationChannel(notificationChannel);
}
private void DispatchNotificationThatServiceIsRunning()
{
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.SetDefaults((int)NotificationDefaults.All)
.SetSmallIcon(Resource.Drawable.icon)
.SetVibrate(new long[] { 100, 200, 300, 400, 500, 400, 300, 200, 400 })
.SetSound(null)
.SetChannelId(NOTIFICATION_CHANNEL_ID)
.SetPriority(NotificationCompat.PriorityDefault)
.SetAutoCancel(false)
.SetContentTitle("Mobile")
.SetContentText("My service started")
.SetOngoing(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.From(this);
notificationManager.Notify(NOTIFICATION_SERVICE_ID, builder.Build());
}
private void DispatchNotificationThatAlarmIsGenerated(string message)
{
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.OneShot);
Notification.Builder notificationBuilder = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
.SetSmallIcon(Resource.Drawable.icon_round)
.SetContentTitle("Alarm")
.SetContentText(message)
.SetAutoCancel(true)
.SetContentIntent(pendingIntent);
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Notify(App.NOTIFICATION_ALARM, notificationBuilder.Build());
}
This is just a sample, the code is not making any HTTP requests, nor works with entities, db connection etc, it just simply dispatches a new notification every X seconds. What I should see is, when application is closed, the service starts and native notification is created, which is what I see. Then for some time I see 'Alarm' notification is being generated and then my service notification is killed, service disposed and that is all. If I click the power button on my phone, to light up the screen, I see 'Alarm' notifications come to live again. I've checked on several mobile devices with different Android OS (6, 7 and 8) and with disabled power saving modes, no difference, the service notification is killed. What is the issue, what am I doing wrong?
Thanks in advance for any help or guidance!