如何在我的Xamarin应用程序的后台运行方法?

一旦应用程序打开并运行,我想要一个后台进程来检查数据库并根据数据库中的数据进行更新。 我想每隔一分钟做一次检查。 我只希望在应用程序位于前台并且在用户视图中时发生这种情况。

有人可以给我一些关于我这样做的建议吗? 我假设我可以从这里调用一个方法,但我不知道该怎么做。 此外,我不知道如何停止,甚至我需要手动取消/停止该过程。 当应用程序不在前台时会自动取消并在应用程序返回到前台时重新启动吗?

public partial class App : Application { protected override void OnStart() { App.DB.InitData(); MainPage = new Japanese.MainPage(); } 

但我是否需要在不同的线程上运行此操作,如果是,我该怎么做呢。

对不起,如果我的问题不明确。 请问,如果没有意义我可以更新。

我们在表单应用程序中所做的是利用System.Diagnostics中可用的Device.Timer和Stopwatch类,以及Xamarin.Forms创建一个非常通用的托管计时器,我们可以使用onStart,onSleep和onResume进行交互。 Xamarin.Forms中的方法。

此特定解决方案不需要任何特殊的平台特定逻辑,并且设备计时器和秒表是非UI阻止。

 using Xamarin.Forms; using System; using System.Linq; using System.Diagnostics; namespace YourNamespace { public partial class App : Application { private static Stopwatch stopWatch = new Stopwatch(); private const int defaultTimespan = 1; protected override void OnStart() { // On start runs when your application launches from a closed state, if (!StopWatch.IsRunning) { StopWatch.Start(); } Device.StartTimer(new TimeSpan(0, 0, 1), () => { // Logic for logging out if the device is inactive for a period of time. if (StopWatch.IsRunning && StopWatch.Elapsed.Minutes >= defaultTimespan) { //prepare to perform your data pull here as we have hit the 1 minute mark // Perform your long running operations here. InvokeOnMainThread(()=>{ // If you need to do anything with your UI, you need to wrap it in this. }); stopwatch.Restart(); } // Always return true as to keep our device timer running. return true; }); } protected override void OnSleep() { // Ensure our stopwatch is reset so the elapsed time is 0. StopWatch.Reset(); } protected override void OnResume() { // App enters the foreground so start our stopwatch again. StopWatch.Start(); } } } 

编辑:

关于上述解决方案如何逐步运作的一些背景:

应用程序从关闭状态开始,’OnStart()’方法创建我们的每秒滴答的Device.Timer。 它也开始我们的秒表计数一分钟。

当应用程序进入后台时,如果我们将’false’值传递给我们的Device.StartTimer()操作,它将在此时点击’OnSleep’方法,它将无法再次启动。 因此,我们只需在应用程序再次打开时重置我们的秒表。

当应用程序返回到前台时,它会点击“OnResume”方法,该方法只会启动现有的秒表。

2018编辑:

这个答案在2018年仍有一些优点,但主要针对非常具体的情况。 即使在Xamarin.Forms中,也有更好的平台特定方式来复制此function。 考虑到用户活动/不活动,上述仍然是在一段时间后执行任务的平台无关的方式。

你可以用这个,

  System.Threading.Tasks.Task.Run(() => { //Add your code here. }).ConfigureAwait(false); 

要运行后台任务,请使用服务 。 通常将任务分类为长时间运行任务或周期性任务。

android中的服务代码如下所示

 [Service] public class PeriodicService : Service { public override IBinder OnBind(Intent intent) { return null; } public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId) { // From shared code or in your PCL return StartCommandResult.NotSticky; } } 

并在后台调用服务

  var intent = new Intent (this, typeof(PeriodicService)); StartService(intent); 

如果想在每分钟后调用和检查

 private void StartBackgroundDataRefreshService () { var pt = new PeriodicTask.Builder () .SetPeriod (1800) // in seconds; minimum is 30 seconds .SetService (Java.Lang.Class.FromType (typeof(BackgroundService))) .SetRequiredNetwork (0) .SetTag (your package name) // package name .Build (); GcmNetworkManager.GetInstance (this).Schedule (pt); } 

要了解哪种服务类型适合您,请阅读本教程 服务类型

Xamarin博客定期后台服务 Xamarin服务博客

另一个例子是

 public class PeriodicService : Service { private static Timer timer = new Timer(); public override IBinder OnBind(Intent intent) { return null; } public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId) { timer.scheduleAtFixedRate(new mainTask(), 0, 5000); return StartCommandResult.NotSticky; } private class mainTask extends TimerTask { public void run() { //your code } } } 

这是XAMARIN Android服务的示例代码,它将在每10秒后执行一次任务

 using System; using System.Threading; using Android.App; using Android.Content; using Android.OS; using Android.Util; namespace SimpleService { [Service] public class SimpleStartedService : Service { static readonly string TAG = "X:" + typeof(SimpleStartedService).Name; static readonly int TimerWait = 10000; Timer timer; DateTime startTime; bool isStarted = false; public override void OnCreate() { base.OnCreate(); } public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId) { Log.Debug(TAG, $"OnStartCommand called at {startTime}, flags={flags}, startid={startId}"); if (isStarted) { TimeSpan runtime = DateTime.UtcNow.Subtract(startTime); Log.Debug(TAG, $"This service was already started, it's been running for {runtime:c}."); } else { startTime = DateTime.UtcNow; Log.Debug(TAG, $"Starting the service, at {startTime}."); timer = new Timer(HandleTimerCallback, startTime, 0, TimerWait); isStarted = true; } return StartCommandResult.NotSticky; } public override IBinder OnBind(Intent intent) { // This is a started service, not a bound service, so we just return null. return null; } public override void OnDestroy() { timer.Dispose(); timer = null; isStarted = false; TimeSpan runtime = DateTime.UtcNow.Subtract(startTime); Log.Debug(TAG, $"Simple Service destroyed at {DateTime.UtcNow} after running for {runtime:c}."); base.OnDestroy(); } void HandleTimerCallback(object state) { TimeSpan runTime = DateTime.UtcNow.Subtract(startTime); Log.Debug(TAG, $"This service has been running for {runTime:c} (since ${state})." ); } } 

}

在iOS和Android中有几种方法可以做到这一点。 在Xamarin Forms中,大部分function属于Backgrounding的绰号。 那里有很多教程。 这个非常详细,绝对值得一试:

http://arteksoftware.com/backgrounding-with-xamarin-forms/

在Android中,很多这项工作都是在后台服务中完成的 。 对于iOS,请查看长时间运行有限长度任务 。 从这一点可以看出,没有Xamarin Forms这样做的方法。 您将需要编写Xamarin.Android和Xamarin.iOS特定代码。

您可以使用

 Device.StartTimer(TimeSpan.FromMinutes(1), () => { var shouldTimerContinueWork = true; /*your code*/ return shouldTimerContinueWork; }); 

此计时器在后台线程上运行,使用设备时钟和重入安全。
要在应用程序处于后台时停止此计时器,您可以使用Xamarin.Forms.Application方法OnSleepOnResume ,如此处所述

我正在做这样的事情是我的Xamarin Forms应用程序。

 public void execute() { var thread = new Thread(new ThreadStart(startAuthenticationProcess)) { IsBackground = true }; thread.Start(); } private void startAuthenticationProcess() { Thread.Sleep(2000); if (!Utils.isNetworkAvailable(splashActivity)) { splashActivity.RunOnUiThread(() => Utils.showToast(splashActivity, splashActivity.GetString(Resource.String.r30025))); splashActivity.FinishAffinity(); } else { try { if (StringUtils.isBlank(strIPAdd) || (StringUtils.isNotBlank(strIPAdd) && (StringUtils.isBlank(strDbName) || "site".Equals(strDbName,StringComparison.OrdinalIgnoreCase)))) { splashActivity.RunOnUiThread(() => DependencyService.Get().showAuthenticationDialog(new Command(() => { var intent = new Intent(splashActivity, typeof(MainActivity)); intent.PutExtra("startLoginActivity", false); splashActivity.StartActivity(intent); splashActivity.Finish(); }))); } else { gotoLoginScreen(); } } catch (Exception e) { Log.Error(TAG, e.Message); } } } 

很容易,尝试这样的东西,并在这些方法中实现您的逻辑:

 public partial class App : Application { protected override void OnStart() { // Your App On start code should be here... // and then: Task.Run(() => { //Add your code here, it might looks like: CheckDatabase(); MakeAnUpdateDependingOnDatabase(); }); } 

我希望它有所帮助。