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

Ala*_*an2 32 c# xamarin xamarin.forms

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

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

public partial class App : Application
{

   protected override void OnStart()
   {
      App.DB.InitData();
      MainPage = new Japanese.MainPage();
   }
Run Code Online (Sandbox Code Playgroud)

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

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

Man*_*rma 21

你可以用这个,

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


Dig*_*1nt 17

我们在表单应用程序中所做的是使用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.

                        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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


编辑:

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

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

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

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

2018编辑:

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

  • 为什么要使用StopWatch?计时器已经为你做了.StopWatch + Task.Run在计时器委托内添加重入.为什么使用Task.Run在主线程上调用?为什么保持计时器始终运行?为什么选择StopWatch.restart(); 和停止(); 而只是重置();?maaan (2认同)

Ste*_*sen 9

在iOS和Android中有几种方法可以做到这一点.在Xamarin Forms中,大部分功能属于Backgrounding的绰号.那里有很多教程.这个很精致,绝对值得一试:

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

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


Ram*_*dom 9

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

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

并在后台调用服务

   var intent = new Intent (this, typeof(PeriodicService));
   StartService(intent);
Run Code Online (Sandbox Code Playgroud)

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

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);
}
Run Code Online (Sandbox Code Playgroud)

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

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
        }
    } 
}
Run Code Online (Sandbox Code Playgroud)

这是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})." );
    }
}
Run Code Online (Sandbox Code Playgroud)

}


Iva*_*kin 7

您可以使用

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

此计时器在后台线程上运行,使用设备时钟和重入安全.
要停止该定时器,当应用程序在后台,你可以使用Xamarin.Forms.Application方法OnSleep的onResume描述这里


Abh*_*ash 5

我正在做类似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);
                }
            }
        }
Run Code Online (Sandbox Code Playgroud)


Jua*_*uan 5

很简单,尝试这样的事情并在这些方法中实现你的逻辑:

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();
        });
   }
Run Code Online (Sandbox Code Playgroud)

我希望它有帮助。