Попытался реализовать работу фоновой задачи в Android и iOS как это описано в статье.
Для этого в MainPage
я создал Label
с именем ticker
и в код формы добавил следующий код:
В конструкторе вызываю метод HandleReceivedMessages();
, который выглядит следующим образом:
void HandleReceivedMessages()
{
MessagingCenter.Subscribe<TickedMessage>(this, "TickedMessage", message =>
{
Device.BeginInvokeOnMainThread(() =>
{
try
{
ticker.Text = message.Message;
}
catch { }
});
});
MessagingCenter.Subscribe<CancelledMessage>(this, "CancelledMessage", message =>
{
Device.BeginInvokeOnMainThread(() =>
{
try
{
ticker.Text = "Cancelled";
}
catch { }
});
});
}
При нажатии на кнопку запуска задачи выполняется следующий код:
var message = new StartLongRunningTaskMessage();
MessagingCenter.Send(message, "StartLongRunningTaskMessage");
А при нажатие на кнопки остановки следующий:
var message = new StopLongRunningTaskMessage();
MessagingCenter.Send(message, "StopLongRunningTaskMessage");
Также я определил несколько вспомогательных классов:
public class StartLongRunningTaskMessage { }
public class StopLongRunningTaskMessage { }
public class TickedMessage
{
public string Message { get; set; }
}
public class CancelledMessage { }
И класс с логикой фоновой задачи:
public class TaskCounter
{
public async Task RunCounter(CancellationToken token)
{
await Task.Run(async () =>
{
for (long i = 0; i < long.MaxValue; i++)
{
token.ThrowIfCancellationRequested();
await Task.Delay(250);
TickedMessage message = new TickedMessage {Message = i.ToString()};
Device.BeginInvokeOnMainThread(() => { MessagingCenter.Send(message, "TickedMessage"); });
}
}, token);
}
}
В Android-проекте в MainActivity.cs в метод OnCreate я добавил следующий код:
MessagingCenter.Subscribe<StartLongRunningTaskMessage> (this, "StartLongRunningTaskMessage", message => {
var intent = new Intent (this, typeof(LongRunningTaskService));
StartService (intent);
});
MessagingCenter.Subscribe<StopLongRunningTaskMessage> (this, "StopLongRunningTaskMessage", message => {
var intent = new Intent (this, typeof(LongRunningTaskService));
StopService (intent);
});
А также определил сервис с несколькими методами:
[Service]
public class LongRunningTaskService : Service
{
CancellationTokenSource _cts;
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
TaskCounter counter = new TaskCounter();
counter.RunCounter(_cts.Token).Wait();
}
catch (System.OperationCanceledException) { }
finally
{
if (_cts.IsCancellationRequested)
{
var message = new CancelledMessage();
Device.BeginInvokeOnMainThread(() => MessagingCenter.Send(message, "CancelledMessage"));
}
}
}, _cts.Token);
return StartCommandResult.Sticky;
}
public override void OnDestroy()
{
if (_cts != null)
{
_cts.Token.ThrowIfCancellationRequested();
_cts.Cancel();
}
base.OnDestroy();
}
}
В iOS-проекте в AppDelegate.cs в метод FinishedLaunching добавил следующий код:
MessagingCenter.Subscribe<StartLongRunningTaskMessage>(this, "StartLongRunningTaskMessage", async message =>
{
_longRunningTaskExample = new iOSLongRunningTaskExample();
await _longRunningTaskExample.Start();
});
MessagingCenter.Subscribe<StopLongRunningTaskMessage>(this, "StopLongRunningTaskMessage",
message => { _longRunningTaskExample.Stop(); });
И также определил класс:
public class iOSLongRunningTaskExample
{
nint _taskId;
CancellationTokenSource _cts;
public async Task Start()
{
_cts = new CancellationTokenSource();
_taskId = UIApplication.SharedApplication.BeginBackgroundTask("LongRunningTask", OnExpiration);
try
{
//INVOKE THE SHARED CODE
TaskCounter counter = new TaskCounter();
await counter.RunCounter(_cts.Token);
}
catch (OperationCanceledException) { }
finally
{
if (_cts.IsCancellationRequested)
{
var message = new CancelledMessage();
Device.BeginInvokeOnMainThread(() => MessagingCenter.Send(message, "CancelledMessage"));
}
}
UIApplication.SharedApplication.EndBackgroundTask(_taskId);
}
public void Stop()
{
_cts.Cancel();
}
void OnExpiration()
{
_cts.Cancel();
}
}
В результате запущенная в "активном" режиме работы приложения задача останавливается, когда я закрываю приложение. В чем может быть дело? На видео у автора статьи все работает, а у меня почему-то нет. Может ли быть причина в том, что данный метод уже устарел и для реализации фоновой задачи требуются дополнительные действия?
По умолчанию служба запускается в том же процессе, что и приложение Android. Можно запустить службу в собственном процессе, задав для свойства ServiceAttribute.IsolatedProcess значение true
https://docs.microsoft.com/ru-ru/xamarin/android/app-fundamentals/services/creating-a-service/
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
У меня есть консольное приложение с подключённой сборкой PresentationCore(тесты делаются здесь - так проще; проверял в оконном приложении и результаты...
Хотите улучшить этот вопрос? Обновите вопрос так, чтобы он вписывался в тематику Stack Overflow на русском