web-dev-qa-db-ja.com

アプリが開いて実行されているときにのみバックグラウンドでメソッドを実行する方法は?

アプリがopen and runningになったら、データベースをチェックし、データベース内のデータに応じて更新を行うバックグラウンドプロセスが必要です。このチェックを1分ごとに行いたいと思います。これは、アプリがフォアグラウンドにあり、ユーザーの視界に入っているときにのみ発生します。

誰かが私がこれをどのように行うかについていくつかの提案をすることができますか?ここからメソッドを呼び出すことができると思いますが、これを行う方法がわかりません。また、停止する方法がわからず、プロセスを手動でキャンセル/停止する必要がある場合でも。アプリがフォアグラウンドにないときに自動的にキャンセルし、アプリがフォアグラウンドに戻ったときに再起動しますか?

public partial class App : Application
{

   protected override void OnStart()
   {
      App.DB.InitData();
      MainPage = new Japanese.MainPage();
   }

しかし、これを別のスレッドで実行する必要がありますか?.

私の質問が明確でない場合は申し訳ありません。質問してください、それが意味をなさない場合は更新できます。

32
Alan2

フォームアプリケーションで行ったことは、System.DiagnosticsおよびXamarin.Formsで使用可能なDevice.TimerとStopwatchクラスを使用して、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();
        }
    }
}


編集:

上記のソリューションがどのように段階的に機能するかに関するコンテキストを提供するには:

アプリケーションは閉じた状態から開始し、「OnStart()」メソッドは1秒ごとにティックするDevice.Timerを作成します。また、1分までカウントするストップウォッチも開始します。

アプリがバックグラウンドになると、「false」値をDevice.StartTimer()アクションに渡すと、この時点で「OnSleep」メソッドにヒットし、再起動しません。その代わりに、アプリを再度開いたときに備えてストップウォッチをリセットするだけです。

アプリがフォアグラウンドに戻ると、「OnResume」メソッドにヒットし、既存のストップウォッチが開始されます。

2018編集:

この回答には2018年でもまだいくつかのメリットがありますが、主に非常に特定の状況です。 Xamarin.Formsでもこの機能を複製するには、プラットフォーム固有のより良い方法があります。上記は、ユーザーのアクティビティ/非アクティビティを考慮して、一定期間後にタスクを実行するプラットフォームに依存しない方法です。

17
Digitalsa1nt

これを使用できます

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

バックグラウンドタスクを実行するには、Serviceを使用します。通常、タスクは長時間実行タスクまたは定期タスクのいずれかに分類されます。

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
        }
    } 
}

10秒ごとにタスクを実行するXAMARIN Androidサービスのサンプルコードを次に示します

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})." );
    }
}

}

9
Ramankingdom

IOSとAndroidの両方でこれを行う方法がいくつかあります。 Xamarin Formsでは、この機能のほとんどはBackgroundingという名前に分類されます。そこには多くのチュートリアルがあります。これは非常に精巧であり、間違いなくチェックする価値があります:

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

Androidでは、この作業の多くはBackground Serviceで行われます。 iOSの場合は、Long RunningまたはFinite-Length Tasksを参照してください。これからわか​​るように、Xamarin Formsでこれを行う方法はありません。 Xamarin.AndroidおよびXamarin.iOS固有のコードを記述する必要があります。

8

使用できます

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

このタイマーはバックグラウンドスレッドで実行され、デバイスのクロックと再入可能セーフを使用します。
アプリがバックグラウンドにあるときにこのタイマーを停止するには、Xamarin.Forms.Applicationメソッドを使用できますOnSleepおよびOnResume説明通り here

7
Ivan Bukashkin

このようなことをしているのが、私の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);
                }
            }
        }
5
Abhinash

簡単で、次のようなものを試して、これらのメソッドにロジックを実装します。

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();
        });
   }

役に立てば幸いです。

4
Juan