Reputation: 1
I'd like to know how can I convert this functions for running in the background (Running even if the app is closed or the phone was restarted)
This is the code which I'd like to convert:
private async void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
try
{
#region TaskHere
// Implement your task here
var locales = await TextToSpeech.GetLocalesAsync();
// Grab the first locale
var locale = locales.FirstOrDefault();
var settings = new SpeechOptions()
{
Volume = 1.0f,
Pitch = 0.70f,
Locale = locale
};
await TextToSpeech.SpeakAsync(_Item.Description, settings);
await Task.Delay(2000);
await TextToSpeech.SpeakAsync(_Item.Description, settings);
await Task.Delay(2000);
await TextToSpeech.SpeakAsync(_Item.Description, settings);
#endregion
}
catch (Exception ex)
{
Console.Write(ex.ToString());
throw;
}
// Task to run every 5 hours on each target day of the week
}
The function is called in a CRUD, everything work well, only when the app is closed or the phone is shutdown or restarted the app doesn't work.
I Hope you can help me.
The complete code would be this:
CRUD:
using Android.Content;
using Android.Widget;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using ToDo.App.Models;
using Xamarin.Essentials;
namespace ToDo.App.Services
{
public class SchedulerTaskService
{
ToDoItem _Item;
Android.Content.Context _context;
public SchedulerTaskService()
{
}
public SchedulerTaskService(ToDoItem Item, Android.Content.Context context)
{
_Item = Item;
_context = context;
}
public async Task<ToDoItem> ScheduleTask()
{
var lstDeserializeListOfWeek = JsonConvert.DeserializeObject<List<DayOfWeekModel>>(_Item.ObjDaysToRepeat);
List<DayOfWeek> targetDays = await GetDaysFromModel(lstDeserializeListOfWeek);
// Define the target days of the week
//List<DayOfWeek> targetDays = JsonConvert.DeserializeObject<List<DayOfWeek>>(_Item.ObjDaysToRepeat);
List<System.Timers.Timer> lstTimers = new List<System.Timers.Timer>();
await Task.Run(() =>
{
// Schedule timer for each target day of the week
foreach (DayOfWeek targetDay in targetDays)
{
// Get the next target day
DateTime today = DateTime.Today;
int daysUntilNextTargetDay = ((int)targetDay - (int)today.DayOfWeek + 7) % 7;
DateTime nextTargetDay = today.AddDays(daysUntilNextTargetDay);
// Set the start time for the timer
TimeSpan startTime = new TimeSpan(_Item.Hour.Hours, _Item.Hour.Minutes, _Item.Hour.Seconds);
DateTime startDateTime = nextTargetDay + startTime;
// Calculate the initial delay until the first timer elapses
TimeSpan initialDelay = startDateTime - DateTime.Now;
// Set timer properties
var timer = new System.Timers.Timer(initialDelay.TotalMilliseconds > 0 ? initialDelay.TotalMilliseconds : initialDelay.TotalMilliseconds * -1);
//var timer = new System.Timers.Timer();
if (_Item.WithInterval != 0)
{
timer.Interval = TimeSpan.FromHours(_Item.WithInterval).TotalMilliseconds;
}
//timer.AutoReset = true;
// Start the timer
timer.Elapsed += OnTimerElapsed;
timer.Start();
lstTimers.Add(timer);
}
});
_Item.ObjTimer = JsonConvert.SerializeObject(lstTimers.ToList());
int result = await App.Context.InsertItemAsync(_Item);
if (result == 1)
return _Item;
else
CancelTask(lstTimers);
return null;
}
public async Task<ToDoItem> EditScheduleAsync()
{
var lstDeserializeListOfWeek = JsonConvert.DeserializeObject<List<DayOfWeekModel>>(_Item.ObjDaysToRepeat);
List<DayOfWeek> targetDays = await GetDaysFromModel(lstDeserializeListOfWeek);
// Define the target days of the week
List<System.Timers.Timer> lstTimers = new List<System.Timers.Timer>();
CancelTask(JsonConvert.DeserializeObject<List<System.Timers.Timer>>(_Item.ObjTimer));
await Task.Run(() =>
{
// Schedule timer for each target day of the week
foreach (DayOfWeek targetDay in targetDays)
{
// Get the next target day
DateTime today = DateTime.Today;
int daysUntilNextTargetDay = ((int)targetDay - (int)today.DayOfWeek + 7) % 7;
DateTime nextTargetDay = today.AddDays(daysUntilNextTargetDay);
// Set the start time for the timer
TimeSpan startTime = new TimeSpan(_Item.Hour.Hours, _Item.Hour.Minutes, _Item.Hour.Seconds);
DateTime startDateTime = nextTargetDay + startTime;
// Calculate the initial delay until the first timer elapses
TimeSpan initialDelay = startDateTime - DateTime.Now;
// Set timer properties
var timer = new System.Timers.Timer(initialDelay.TotalMilliseconds > 0 ? initialDelay.TotalMilliseconds : initialDelay.TotalMilliseconds * -1);
//var timer = new System.Timers.Timer();
if (_Item.WithInterval != 0)
{
timer.Interval = TimeSpan.FromHours(_Item.WithInterval).TotalMilliseconds;
}
//timer.AutoReset = true;
// Start the timer
timer.Elapsed += OnTimerElapsed;
timer.Start();
lstTimers.Add(timer);
}
});
_Item.ObjTimer = JsonConvert.SerializeObject(lstTimers.ToList());
_Item.CreateTime = DateTime.Now;
int result = await App.Context.EditItemAsync(_Item);
if (result == 1)
return _Item;
else
CancelTask(lstTimers);
return null;
}
private async void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
try
{
#region TaskHere
// Implement your task here
var locales = await TextToSpeech.GetLocalesAsync();
// Grab the first locale
var locale = locales.FirstOrDefault();
var settings = new SpeechOptions()
{
Volume = 1.0f,
Pitch = 0.70f,
Locale = locale
};
await TextToSpeech.SpeakAsync(_Item.Description, settings);
await Task.Delay(2000);
await TextToSpeech.SpeakAsync(_Item.Description, settings);
await Task.Delay(2000);
await TextToSpeech.SpeakAsync(_Item.Description, settings);
#endregion
}
catch (Exception ex)
{
Console.Write(ex.ToString());
throw;
}
// Task to run every 5 hours on each target day of the week
}
public async void CancelTask(List<System.Timers.Timer> InLstTimers)
{
await Task.Run(() =>
{
foreach (var item in InLstTimers)
{
item.Enabled = false;
item.Dispose();
item.Stop();
}
});
}
private async Task<List<DayOfWeek>> GetDaysFromModel(List<DayOfWeekModel> ModelWeek)
{
List<System.DayOfWeek> lstselectedDays = new List<System.DayOfWeek>();
#region LllenadoListaDayOfWeek
await Task.Run(() =>
{
//listViewDaysOfWeek.ItemsSource
foreach (DayOfWeekModel item in ModelWeek)
{
if (item.IsChecked)
{
switch (item.DayOfWeek)
{
case "Monday":
lstselectedDays.Add(System.DayOfWeek.Monday);
break;
case "Tuesday":
lstselectedDays.Add(System.DayOfWeek.Tuesday);
break;
case "Wednesday":
lstselectedDays.Add(System.DayOfWeek.Wednesday);
break;
case "Thursday":
lstselectedDays.Add(System.DayOfWeek.Thursday);
break;
case "Friday":
lstselectedDays.Add(System.DayOfWeek.Friday);
break;
case "Saturday":
lstselectedDays.Add(System.DayOfWeek.Saturday);
break;
case "Sunday":
lstselectedDays.Add(System.DayOfWeek.Sunday);
break;
default:
break;
}
}
}
});
#endregion
return lstselectedDays;
}
}
}
I call some CRUD function in the c# part of a view:
using Android.App;
using Android.App.Job;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ToDo.App.Models;
using ToDo.App.Services;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific.AppCompat;
using Android.App.AppSearch;
using Android;
using Java.Sql;
using System.Threading;
using Android.OS;
using Android.Content;
using Xamarin.Essentials;
using static Android.Content.ClipData;
using static Android.OS.Build;
using Newtonsoft.Json;
using Android.Widget;
using ToDo.App.Strategy;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
using Android.Text.Format;
using System.ComponentModel;
//using static Android.InputMethodServices.Keyboard;
//using static Android.Util.EventLogTags;
//using Java.Lang;
namespace ToDo.App.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AddPage : ContentPage
{
//JobScheduler jobScheduler;
//ServiceDownloadJob service;
private CancellationTokenSource cancelSource;
ToDoItem result = null;
int EditItemId = 0;
bool isEdit = false;
bool isAddInterval = false;
List<DayOfWeekModel> daysOfWeekList = null;
public AddPage()
{
InitializeComponent();
FillcboDayOfWeek();
}
public AddPage(ToDoItem item)
{
InitializeComponent();
FillFields(item);
}
private async void BtnGuardar_Clicked(object sender, EventArgs e)
{
try
{
var selectedDays = daysOfWeekList.Where(d => d.IsChecked).ToList();
if (String.IsNullOrEmpty(nombre.Text) || String.IsNullOrEmpty(descripcion.Text) || selectedDays.Count() <= 0)
{
await DisplayAlert("Error", "No puedes dejar campos vacíos.\n\n", "Aceptar");
return;
}
var existName = await App.Context.FindItemByNameAsync(nombre.Text);
if (existName != null && !isEdit)
{
await DisplayAlert("Error", "No puedes tener más de una tarea con el mismo nombre.\n\n" + " Porfavor elige otro nombre para tu tarea", "Aceptar");
return;
}
//ValidationForm(selectedDays);
var context = Android.App.Application.Context;
ToDoItem inItem = new ToDoItem();
if(isEdit)
inItem = await App.Context.FindItemAsync(EditItemId);
await Task.Run(() =>
{
inItem.WithInterval = 0;
inItem.Hour = TimePicker.Time;
inItem.Name = nombre.Text;
inItem.Description = descripcion.Text;
// iterar sobre la lista de modelos de días de la semana
// get list of selected days
inItem.ObjDaysToRepeat = JsonConvert.SerializeObject(selectedDays);
if (isAddInterval && !String.IsNullOrEmpty(txtInterval.Text))
{
inItem.WithInterval = Convert.ToInt32(txtInterval.Text);
inItem.Interval = TimeSpan.FromHours(Convert.ToInt32(txtInterval.Text));
}
});
SchedulerTaskService schedulTaskAsync = new SchedulerTaskService(inItem, context);
if (isEdit)
{
result = await schedulTaskAsync.EditScheduleAsync();
isEdit = false;
EditItemId = 0;
}
else
result = await schedulTaskAsync.ScheduleTask();
if (result != null)
{
//await Task.Delay((int)SleepProccess);
Toast.MakeText(context, "Se programó correctamente la alarma", ToastLength.Short).Show();
await Navigation.PopAsync();
}
else
await DisplayAlert("Error", "No se pudo guardar la tarea", "Aceptar");
}
catch(Exception ex)
{
if (result != null)
{
var findItem = await App.Context.FindItemAsync(result.Id);
var Deleteresult = await App.Context.DeleteItemAsync(result);
List<System.Timers.Timer> CancelDaysAlarm= JsonConvert.DeserializeObject<List<System.Timers.Timer>>(findItem.ObjTimer);
if (Deleteresult == 1)
{
SchedulerTaskService taskScheduler = new SchedulerTaskService();
taskScheduler.CancelTask(CancelDaysAlarm);
}
}
await DisplayAlert("Error", ex.Message, "Aceptar");
}
}
private void CheckBox_CheckedChanged(object sender, CheckedChangedEventArgs e)
{
// handle checkbox checked event
var checkbox = sender as Xamarin.Forms.CheckBox;
var checkedState = checkbox.IsChecked;
var dayOfWeek = checkbox.BindingContext as DayOfWeekModel;
// update the IsChecked property in the DayOfWeekModel object
dayOfWeek.IsChecked = checkedState;
}
private void chkIntervalo_CheckedChanged(object sender, CheckedChangedEventArgs e)
{
lbIntervalo.IsVisible = e.Value;
txtInterval.IsVisible = e.Value;
if (txtInterval.IsVisible)
isAddInterval = true;
else
isAddInterval = false;
}
private void FillcboDayOfWeek()
{
daysOfWeekList = new List<DayOfWeekModel>
{
new DayOfWeekModel { DayOfWeek = "Monday" },
new DayOfWeekModel { DayOfWeek = "Tuesday" },
new DayOfWeekModel { DayOfWeek = "Wednesday" },
new DayOfWeekModel { DayOfWeek = "Thursday" },
new DayOfWeekModel { DayOfWeek = "Friday" },
new DayOfWeekModel { DayOfWeek = "Saturday" },
new DayOfWeekModel { DayOfWeek = "Sunday" }
};
// set the listview's itemssource to the list of days of the week
listViewDaysOfWeek.ItemsSource = daysOfWeekList;
}
private List<DayOfWeekModel> GetDaysLisDayOfWeekModel()
{
daysOfWeekList = new List<DayOfWeekModel>
{
new DayOfWeekModel { DayOfWeek = "Monday", IsChecked = false },
new DayOfWeekModel { DayOfWeek = "Tuesday", IsChecked = false },
new DayOfWeekModel { DayOfWeek = "Wednesday", IsChecked = false },
new DayOfWeekModel { DayOfWeek = "Thursday", IsChecked = false },
new DayOfWeekModel { DayOfWeek = "Friday", IsChecked = false },
new DayOfWeekModel { DayOfWeek = "Saturday", IsChecked = false },
new DayOfWeekModel { DayOfWeek = "Sunday", IsChecked = false }
};
return daysOfWeekList;
}
private async void FillFields(ToDoItem item)
{
try
{
await Task.Run(() =>
{
#region DataEdit
TimePicker.Time = item.Hour;
nombre.Text = item.Name;
descripcion.Text = item.Description;
isEdit = true;
EditItemId = item.Id;
if (item.WithInterval != 0)
{
txtInterval.Text = item.WithInterval.ToString();
chkIntervalo.IsChecked = true;
}
List<DayOfWeekModel> LstCheckedDaysOfWeek = JsonConvert.DeserializeObject<List<DayOfWeekModel>>(item.ObjDaysToRepeat).ToList();
List<DayOfWeekModel> DaysOfWeek = GetDaysLisDayOfWeekModel().ToList();
var lstNotIn = (from c in DaysOfWeek
where !(from o in LstCheckedDaysOfWeek
select o.DayOfWeek)
.Contains(c.DayOfWeek)
select c).ToList();
daysOfWeekList = LstCheckedDaysOfWeek.Union(lstNotIn).ToList();
listViewDaysOfWeek.ItemsSource = daysOfWeekList;
#endregion
});
}
catch (Exception ex)
{
await DisplayAlert("Error", ex.Message, "Aceptar");
}
}
private async void ValidationForm(List<DayOfWeekModel> CheckedDays)
{
//List<DayOfWeekModel>
//var CheckedDays = daysOfWeekList.Where(d => d.IsChecked).ToList();
if (String.IsNullOrEmpty(nombre.Text) || String.IsNullOrEmpty(descripcion.Text) || CheckedDays.Count() <= 0)
{
await DisplayAlert("Error", "No puedes dejar campos vacíos.\n\n", "Aceptar");
return;
}
var existName = await App.Context.FindItemByNameAsync(nombre.Text);
if (existName != null)
{
await DisplayAlert("Error", "No puedes tener más de una tarea con el mismo nombre.\n\n" + " Porfavor elige otro nombre para tu tarea", "Aceptar");
return;
}
}
}
}
Note: My classes are in the shared project, and I'd like to find a solution to follow to work of this way.
I was trying with Shiny.Core, but I had some problems, sorry I'm a noob in Xamarin
Upvotes: 0
Views: 97
Reputation: 4302
As ToolmakerSteve said that you can refer to the answer of this case: How to create a never ending background service in Xamarin.Forms?.
It achieves the effect that app do something in background by ForegroundService of Android.
Upvotes: 0