xamarin Android Service Stops When App Is Closed - c#

I am totally new in Xamarin. I am trying to run the service when the application gets closed. But as I closed the app from the recent item service getting stop and getting message projectname.android has stopped. I want service should run as in whatsapp after closed the app then also service run. Anyone know the answer please help.
Here is my service class Code. This code sent the notification each 5 sec. using local notification plugin library. but this code running fine in android 5 version
class AndroidService : Service
{
private Timer _check_Timer_Data;
public override IBinder OnBind(Intent intent)
{
return null;
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
base.OnStartCommand(intent, flags, startId);
var t = new Thread(() =>
{
_check_Timer_Data = new Timer((o) =>
{
Random rdno = new Random();
int id = rdno.Next(1000);
string dt = DateTime.Now.ToString("h:mm:ss tt");
CrossLocalNotifications.Current.Show("G7CR", "G7CR Notification-" + dt, id);
}, null, 0, 5000);
}
);
t.Start();
return StartCommandResult.Sticky;
}
public override void OnDestroy()
{
base.OnDestroy();
_check_Timer_Data.Dispose();
}
public override void OnCreate()
{
base.OnCreate();
}
}

Related

Xamarin.forms unexpected alarm trigger in backgroud process in Android

I'm just trying to get a multiple countdown counters, when it reaches individually to 0 I want to sound an alert (without any interaction from the user between one and the next).
The countdown is programmed, for instance, to 5, 4 and 7 minutes.
If it's seconds and the app works with the screen ON or just seconds there's no problem, but as soon as it's minutes, the screen turns off and the phone goes into Doze mode (I think), the resulting times are: 5, 6:26 and 9:58 (instead 5,4 and 7).
I've read a lot of user solutions that have been discussed here, but it doesn't work for me.
The phone runs Android v10.
The code to program the Alarm with SetExactAndAllowWhileIdle:
public void ProgAlarm(int nIntervalo) {
var alarmIntent = new Intent(MainActivity.Instance, typeof(AlarmReceiver));
alarmIntent.PutExtra("Contador", nIntervalo);
var pending = PendingIntent.GetBroadcast(MainActivity.Instance, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
MainActivity.alarM.SetExactAndAllowWhileIdle(AlarmType.ElapsedRealtimeWakeup,
SystemClock.ElapsedRealtime()+tiempos[nIntervalo]*1000, pending);
}
And the event triggerd to reprogram the alarm:
[BroadcastReceiver]
public class AlarmReceiver: BroadcastReceiver {
public override void OnReceive(Context context, Intent intent) {
DependencyService.Get<IVarios>().Beep();
int actual=intent.GetIntExtra("Contador",-1);
if (actual!=-1) DependencyService.Get<IVarios>().ProgAlarm(++actual);
}
}
Before the Alarm I tried with PowerManager:
PowerManager pM = (PowerManager)GetSystemService(PowerService);
wakeLock=pM.NewWakeLock(WakeLockFlags.Partial, "CronoMultiple");
[...]
wakeLock.Acquire();
[...]
wakeLock.Release();
and with the flag: WakeLockFlags.AcquireCausesWakeup
But this only works when the screen was always ON, with flag .Partial, the screen turns off and the app stops and the counter doesn't work. In the PC emulator it works (even with adb commands), but not on the phone.
Any solution without using a Service? (I'm new to Xamarin.forms).
Here is a simple sample ,it will alarm every 1 min:
interface IVarios
public interface IVarios
{
void ProgAlarm(int minute);
}
in MainActivity,let it implement IVarios :
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity,IVarios
{
public void ProgAlarm(int minute)
{
Intent intent = new Intent(MainActivity.Instance, typeof(LongRunningService));
intent.PutExtra("Contador", minute);
MainActivity.Instance.StartService(intent);
}
}
in Android project,create LongRunningService :
[Service]
class LongRunningService : Service
{
int minutes;
public override IBinder OnBind(Intent intent)
{
return null;
}
public override void OnCreate()
{
base.OnCreate();
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
Android.Util.Log.Error("LongRunningService", "executed");
AlarmManager manager = (AlarmManager)GetSystemService(AlarmService);
int min = intent.GetIntExtra("Contador", -1);
minutes = min != -1 ? min : minutes;
int anHour = minutes * 60 * 1000; // Number of milliseconds
long triggerAtTime = SystemClock.ElapsedRealtime() + anHour;
Intent i = new Intent(this, typeof(AlarmReceiver));
PendingIntent pi = PendingIntent.GetBroadcast(this, 0, i, PendingIntentFlags.UpdateCurrent);
manager.SetExactAndAllowWhileIdle(AlarmType.ElapsedRealtimeWakeup, triggerAtTime, pi);
return StartCommandResult.Sticky;
}
}
in Android project,create AlarmReceiver :
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { Android.Content.Intent.ActionBootCompleted })]
class AlarmReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Intent i = new Intent(context, typeof(LongRunningService));
context.StartService(i);
}
}
Then you could call it in your page like :
DependencyService.Get<IVarios>().ProgAlarm(1);

Calling methods from PCL to android - Xamarin

How can I call method defined in my PCL project to Android project ?
I have a method DoWork() defined in my PCL and I want this method to continuously be run in a service defined in my android project as follows:
public class BroadcastService : Service
{
IBinder mBinder;
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
Toast.MakeText(this, "BroadcastService is running ", ToastLength.Long).Show();
Task.Run(() =>
{
var counter = new Counter();
counter.DoWork().Wait();
});
base.OnStartCommand(intent, flags, startId);
return StartCommandResult.Sticky;
}
The toast is appearing.
However, the DoWork() is not running. Can someone enlighten what is wrong please?
The full method signature for DoWork() :
private async void DoWork()
{
StartDetect();
Device.StartTimer(TimeSpan.FromSeconds(20), () =>
{
_foundTags = _truck.GetAvailableTrucks();
DoWork();
});
}
I think you can use a MessagingCenter. You can try something like this
public class BroadcastService : Service
{
IBinder mBinder;
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
Toast.MakeText(this, "BroadcastService is running ", ToastLength.Long).Show();
Xamarin.Forms.MessagingCenter.Send<App>((App)Xamarin.Forms.Application.Current, "dowork");
base.OnStartCommand(intent, flags, startId);
return StartCommandResult.Sticky;
}
and in your PCL project
protected override void OnStart()
{
MessagingCenter.Subscribe<App>(this, "dowork", (sender) =>
{
// Do something here
});
// Handle when your app starts
}

Xamarin forms background service is killed when app is killed

I am making use of Prism in my xamarin forms project.I am also making use of background services to push long running tasks in the background.The problem is when the app is killed the service is also killed.And by "killed" I mean press home-button -> see all running apps -> swipe my app aside -> app killed .I want to keep the service alive even if the app is killed.I have read many posts which say that it can be done.However I was not able to get it working.
This is what I have tried :-
This is Android MainActivity.cs
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
try
{
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App(new AndroidInitializer()));
WireUpLongRunningTask();
}
catch(Exception)
{
}
}
public void WireUpLongRunningTask()
{
MessagingCenter.Subscribe<StartSyncBackgroundingTask>(this, "StartSyncBackgroundingTask", message => {
var intent = new Intent(this, typeof(AndroidSyncBackgroundService));
StartService(intent);
});
}
This is AndroidSyncBackgroundService class :-
[Service]
public class AndroidSyncBackgroundService : Service
{
CancellationTokenSource _cts;
private ISyncBackgroundService _isyncBackgroundService;
private App _app => (App)Xamarin.Forms.Application.Current;
public override IBinder OnBind(Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
_cts = new CancellationTokenSource();
Task.Run(() => {
try {
//INVOKE THE SHARED CODE
_isyncBackgroundService = _app.Container.Resolve<ISyncBackgroundService>();
_isyncBackgroundService.RunBackgroundingCode(_cts.Token).Wait();
}
catch (System.OperationCanceledException) {
}
finally {
if (_cts.IsCancellationRequested) {
var message = new CancelledTask();
Device.BeginInvokeOnMainThread(
() => MessagingCenter.Send(message, "CancelledTask")
);
}
}
}, _cts.Token);
return StartCommandResult.Sticky;
}
public override void OnDestroy()
{
if (_cts != null) {
_cts.Token.ThrowIfCancellationRequested();
_cts.Cancel();
}
StartService(new Intent("com.xamarin.AndroidSyncBackgroundService"));
base.OnDestroy();
}
public override void OnTaskRemoved(Intent rootIntent)
{
Intent restartServiceIntent = new Intent(Xamarin.Forms.Forms.Context, typeof(AndroidSyncBackgroundService));
PendingIntent restartServicePendingIntent = PendingIntent.GetService(Xamarin.Forms.Forms.Context, 1, restartServiceIntent,PendingIntentFlags.OneShot);
AlarmManager alarmService = (AlarmManager)Xamarin.Forms.Forms.Context.GetSystemService(Context.AlarmService);
alarmService.Set(
AlarmType.ElapsedRealtime,
1000,
restartServicePendingIntent);
base.OnTaskRemoved(rootIntent);
}
}
This is SyncBackgroundService class :-
public class SyncBackgroundService: ISyncBackgroundService
{
private ISqliteCallsService _iSqliteCallsService;
private IFeedBackSqliteService _feedBackSqliteService;
private ISettingApiService _isettingApiService;
private ISettingSqliteService _isettingSqliteService;
private IWebApiService _iwebApiService;
private App _app => (App)Xamarin.Forms.Application.Current;
public async Task RunBackgroundingCode(CancellationToken token)
{
_iSqliteCallsService= _app.Container.Resolve<ISqliteCallsService>();
await Task.Run(async () => {
token.ThrowIfCancellationRequested();
App.bRunningBackgroundTask = true;
await Task.Run(async () =>
{
await Task.Delay(1);
_iSqliteCallsService.ftnSaveOnlineModeXMLFormat("Offline", 0);
_iSqliteCallsService.SyncEmployeeTableData();
_iSqliteCallsService.SaveOfflineAppCommentData();
_iSqliteCallsService.SaveOfflineAdditionToFlowData();
await Task.Delay(500);
//MessagingCenter.Send<SyncBackgroundService>(this, "StopSyncBackgroundingTask");
});
}, token);
}
}
}
As can be seen in the code snippet I have made use of StartCommandResult.Sticky and still the service gets killed and does not restart.
Also i'm making use of Alarm Manager in OnTaskRemoved method,which gets fired when the app is killed according to its documentation.But in my case the service does not restart atall.Can somebody point out what is the mistake in my code? Or provide a working solution so that I can implement it in my app.
Thanks in advance!
Try this after you call StartService
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat)
{
PendingIntent pintent = PendingIntent.GetService(AppContext, 0, new Intent(AppContext, typeof(AndroidSyncBackgroundService )), 0);
AlarmManager alarm = (AlarmManager)AppContext.GetSystemService(Context.AlarmService);
alarm.Cancel(pintent);
}
The reason this might work is because Android schedules your service to be killed after your app is killed. Doing this removes that scheduled task.

Xamarin Android Background Service crashes when the Application get closed

Hello, I want to build an app, in which you can start a service, which runs intependenly and creates a notification, and this service should constantly proof, if the DateTime.Now.Date is bigger than a spezific Date.
When I execute the code below, the notification gets displayed, but when I am closing the app, a few secondes later I get two times an information that the app crashed and I dont know why.
I cant even debug the code because this anly happens when the application is closed....
I hope you can help me thanks!
Here is my code:
namespace App
{
[Activity(Label = "App", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
int count = 1;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.MyButton);
button.Click += delegate {
button.Text = string.Format("{0} clicks!", count++);
StartService(new Intent(this, typeof(backgroudservice)));
};
}
}
public class backgroudservice : Service
{
public override IBinder OnBind(Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
newnotification("Title", "Text: ", 0);
new Task(() => {
DoWork();
Thread.Sleep(1000);
}).Start();
return StartCommandResult.Sticky;
}
public void DoWork()
{
if (DateTime.Now.Date > Convert.ToDateTime("2016-03-29").Date)
{
cancelnotification(0);
StopSelf();
}
}
public override void OnDestroy()
{
base.OnDestroy();
cancelnotification(0);
}
private void newnotification(string titel, string text, int id)
{
Notification.Builder builder = new Notification.Builder(this)
.SetContentTitle(titel)
.SetContentText(text)
.SetSmallIcon(Resource.Drawable.droidlogo_small)
.SetAutoCancel(false)
.SetVisibility(NotificationVisibility.Public)
.SetContentIntent(PendingIntent.GetActivity(this, 0, new Intent(this, typeof(MainActivity)), PendingIntentFlags.OneShot));
// Build the notification:
Notification notification = builder.Build();
notification.Flags = NotificationFlags.NoClear;
//notification.ContentIntent = new Intent(this,typeof(login));
// Get the notification manager:
NotificationManager notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
// Publish the notification:
notificationManager.Notify(id, notification);
}
private void cancelnotification(int id)
{
NotificationManager notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
notificationManager.Cancel(id);
}
}
}
I solved it, I forgot the [Service] above my class, now it works!
[Service]
public class backgroudservice : Service
{
...
}
You might try moving the call to cancelnotification in your service's OnDestroy to before the call to the base method, i.e.:
public override void OnDestroy()
{
cancelnotification(0);
base.OnDestroy();
}

Background service not work Xamarin.Android

I have problem. My service worked, but when i close application service stoped.
How i can leave my service is running?
service
[Service]
public class NotificationService : Service
{
public NotificationService () { }
public override StartCommandResult OnStartCommand (Android.Content.Intent intent, StartCommandFlags flags, int startId)
{
new Task(() =>
{
DoWork();
} ).Start();
return StartCommandResult.Sticky;
}
public override void OnDestroy ()
{
base.OnDestroy ();
}
public override IBinder OnBind (Intent intent)
{
throw new NotImplementedException ();
}
void DoWork()
{
new Task(() =>
{
for (int i = 0; i < 100; i ++)
{
System.Threading.Thread.Sleep(1000);
var context = Android.App.Application.Context;
var builder = new Android.App.Notification.Builder(context)
.SetSmallIcon(Resource.Drawable.icon)
.SetContentTitle("My application")
.SetDefaults(NotificationDefaults.Sound)
.SetContentText(i.ToString())
.SetOngoing(true);
var not = builder.Build();
var notManager = context.GetSystemService(NotificationService) as NotificationManager;
notManager.Notify(1, not);
}
}).Start();
}
}
MainActivity.cs
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
global::Xamarin.Forms.Forms.Init (this, bundle);
LoadApplication (new App ());
new Task(() =>
{
var notificationIntent = new Intent(this, typeof(NotificationService));
StartService(notificationIntent);
}).Start();
Android.Widget.Toast.MakeText(this, "run", Android.Widget.ToastLength.Short).Show();
}
When we start application from VS and stop an application. VS automatically close all services. Need build the app to the device and than start application from device.
Sorry for the late answer but I think it can help others. I would like to make something clear for you that you are writing this service as a background service. Background service can not run for long. There are some limitation of background services in Android after Android 8.0 onwards. Android automatically kills background service of an app after some time.
See this https://developer.android.com/about/versions/oreo/background
If you want to run a service for a long time then make the service Foreground Service. Please follow https://learn.microsoft.com/en-us/xamarin/android/app-fundamentals/services/foreground-services for detailed knowledge of foreground service in Xamarin Forms.

Categories