Xamarin.Android 应用程序关闭后处理的后台任务
Xamarin.Android Background task disposed after application closed
任务:当应用程序 stopped/paused 时,为 运行 创建后台任务,定期(3-7 秒)执行 HTTP 请求并将响应信息存储在 mysqlite 中,并在需要时显示本地通知。
我已经创建了如下后台服务,
[Service(Enabled = true)]
public class MyRequestService : Service
这是从 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();
}
在我的服务中,我使用了以下功能,
- return OnStartCommand 中的 STICKY
- 创建 'permanent' 原生
- 渠道通知
- 电源管理器锁
代码如下所示,
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());
}
这只是一个示例,代码不发出任何 HTTP 请求,也不处理实体、数据库连接等,它只是每隔 X 秒发送一个新通知。我应该看到的是,当应用程序关闭时,服务启动并创建本机通知,这就是我所看到的。然后有一段时间我看到正在生成 'Alarm' 通知,然后我的服务通知被终止,服务被处理,仅此而已。如果我单击 phone 上的电源按钮以点亮屏幕,我会看到 'Alarm' 通知再次出现。我已经检查了几个具有不同 Android OS(6、7 和 8)并且禁用省电模式的移动设备,没有区别,服务通知被终止。问题是什么,我做错了什么?
在此先感谢您的帮助或指导!
我认为你正在使用 Foreground Services。
您应该通过 StartForeground 方法发送服务通知(前台通知)。
所以尝试改变
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 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);
//dispatch foreground notification
StartForeground(NOTIFICATION_SERVICE_ID, builder.Build());
}
任务:当应用程序 stopped/paused 时,为 运行 创建后台任务,定期(3-7 秒)执行 HTTP 请求并将响应信息存储在 mysqlite 中,并在需要时显示本地通知。
我已经创建了如下后台服务,
[Service(Enabled = true)]
public class MyRequestService : Service
这是从 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();
}
在我的服务中,我使用了以下功能,
- return OnStartCommand 中的 STICKY
- 创建 'permanent' 原生
- 渠道通知
- 电源管理器锁
代码如下所示,
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());
}
这只是一个示例,代码不发出任何 HTTP 请求,也不处理实体、数据库连接等,它只是每隔 X 秒发送一个新通知。我应该看到的是,当应用程序关闭时,服务启动并创建本机通知,这就是我所看到的。然后有一段时间我看到正在生成 'Alarm' 通知,然后我的服务通知被终止,服务被处理,仅此而已。如果我单击 phone 上的电源按钮以点亮屏幕,我会看到 'Alarm' 通知再次出现。我已经检查了几个具有不同 Android OS(6、7 和 8)并且禁用省电模式的移动设备,没有区别,服务通知被终止。问题是什么,我做错了什么?
在此先感谢您的帮助或指导!
我认为你正在使用 Foreground Services。
您应该通过 StartForeground 方法发送服务通知(前台通知)。
所以尝试改变
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 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);
//dispatch foreground notification
StartForeground(NOTIFICATION_SERVICE_ID, builder.Build());
}