一旦应用程序打开并运行,我想要一个后台进程来检查数据库并根据数据库中的数据进行更新。我想每隔一分钟做一次检查。我只希望当应用程序在前台并且在用户的视野中时发生这种情况。
有人可以给我一些关于我这样做的建议吗?我假设我可以从这里调用一个方法,但我不知道该怎么做。此外,我不知道如何停止,甚至我需要手动取消/停止该过程。当应用程序不在前台时会自动取消,并在应用程序返回到前台时重新启动吗?
public partial class App : Application
{
protected override void OnStart()
{
App.DB.InitData();
MainPage = new Japanese.MainPage();
}
但我是否需要在不同的线程上运行此操作,如果是,我该怎么做呢。
很抱歉,如果我的问题不明确。请问,如果没有意义,我可以更新。
答案 0 :(得分:20)
你可以使用它,
<button id="lengthbutton" onclick="myFunction()"> Click me to find out length </button>
答案 1 :(得分:13)
我们在表单应用程序中所做的是使用System.Diagnostics中可用的Device.Timer和Stopwatch类,以及Xamarin.Forms创建一个非常通用的托管计时器,我们可以使用onStart与之交互, Xamarin.Forms中的onSleep和onResume方法。
此特定解决方案不需要任何特殊的平台特定逻辑,并且设备计时器和秒表是非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.
Device.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();
}
}
}
修改强>
提供一些关于上述解决方案如何逐步运作的背景信息:
应用程序从关闭状态开始,并且&#39; OnStart()&#39;方法创建我们的每秒滴答的Device.Timer。它也会启动我们的秒表计数到一分钟。
当应用程序进入后台时,它会触及&#39; OnSleep&#39;这个方法,如果我们传递一个假的&#39;值进入我们的Device.StartTimer()操作,它不会再次启动。因此,我们只需在应用程序再次打开时重置我们的秒表即可。
当应用程序返回到前台时,它会点击“OnResume”&#39;方法,它只是启动现有的秒表。
2018年编辑:
即使在2018年,这个答案仍有一些优点,但主要针对非常具体的情况。即使在Xamarin.Forms中,也有更好的平台特定方式来复制此功能。考虑到用户活动/不活动,上述内容仍然是在一段时间后执行任务的平台无关方式。
答案 2 :(得分:8)
要运行后台任务,请使用服务。通常将任务分类为长时间运行任务或周期性任务。
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);
}
为了了解哪种服务类型适合您,请阅读本教程 Types of Services
Xamarin博客定期提供后台服务 Xamarin Service Blog
另一个例子是
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})." );
}
}
}
答案 3 :(得分:7)
在iOS和Android中有几种方法可以做到这一点。在Xamarin Forms中,大多数此功能都属于背景的名称。那里有很多教程。这个很精致,绝对值得一试:
http://arteksoftware.com/backgrounding-with-xamarin-forms/
在Android中,很多工作都是在后台服务中完成的。对于iOS,请查看长时间运行或有限长度任务。从这一点可以看出,没有Xamarin Forms这样做的方法。您需要编写Xamarin.Android和Xamarin.iOS特定代码。
答案 4 :(得分:6)
您可以使用
Device.StartTimer(TimeSpan.FromMinutes(1), () =>
{
var shouldTimerContinueWork = true;
/*your code*/
return shouldTimerContinueWork;
});
此计时器在后台线程上运行,使用设备时钟和重入安全 要在app处于后台时停止此计时器,您可以使用 Xamarin.Forms.Application 方法 OnSleep 和 OnResume ,如上所述here < / p>
答案 5 :(得分:4)
我做这样的事情就是我的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<IAuthenticationDialog>().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);
}
}
}
答案 6 :(得分:3)
很简单,尝试这样的方法并在这些方法中实现你的逻辑:
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();
});
}
我希望它有所帮助。