在Xamarin.ios的ViewModels中在后台运行方法

时间:2018-06-25 03:12:09

标签: ios xamarin xamarin.ios

我正在使用Xamarin.iOS应用程序。我希望我当前正在运行的功能的某些部分也应在后台运行。我有一个System.Timer,它位于App.cs(Load on start)中,并在其中一个viewcontroller中添加了TimerElapsed事件,通过该事件,控件在计时器经过时传递给ViewModel并执行所有功能。

现在,我希望同一功能也可以在后台运行,但是无法思考如何实现它。谁可以帮我这个事?

谢谢。

2 个答案:

答案 0 :(得分:0)

最简单的方法是这样

//某些异步方法

await Task.Run(async () =>
{
 // Code you want to run asynchronously 
 });

祝你好运!

如果查询恢复!

答案 1 :(得分:0)

背景(使用主屏幕按钮将应用程序发送到后台时)在IOS中有点复杂。您可以通过多种方式实现

1)beginBackgroundTaskWithExpirationHandler,但是它有时间限制

2)locationUpdate事件-但是使用计时器时,它的效果不是很好。当您需要不时检查某些东西时,它会更加可疑

3)让您成为应用播放器。播放器即使在后台也可以工作

我使用方法3,对我来说效果很好

您需要在plist文件中添加背景音频的权限

<key>UIBackgroundModes</key>
<array>
    <string>audio</string>
</array>

然后在您的AppDelegate中,需要修改FinishedLaunching方法

    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
        ...
        var currentSession = AVAudioSession.SharedInstance();
        currentSession.SetCategory(AVAudioSessionCategory.Playback, AVAudioSessionCategoryOptions.MixWithOthers);
        currentSession.SetActive(true);
        ...

    }

并添加下一部分,我也将其放在AppDelegat

    #region Background Work

    private BackgroundTask _backgroundTask;

    private readonly Lazy<TouchLogger> _logger = new Lazy<TouchLogger>(() => new TouchLogger());

    public override  void DidEnterBackground(UIApplication uiApplication)
    {
        base.DidEnterBackground(uiApplication);
        startBackgroundTask();
    }      


    public override void WillEnterForeground(UIApplication uiApplication)
    {
        base.WillEnterForeground(uiApplication);

        if (_backgroundTask == null)
        {
            _backgroundTask = new BackgroundTask(_logger.Value);
        }
        else if (_backgroundTask.IsRunned)
        {
            _backgroundTask.Stop();
            _logger.Value.Info("Background", "Task stopped");
        }
    }

    private void startBackgroundTask()
    {
        _logger.Value.Info("Background", "startBackgroundTask() called");

        var needBackgroundActivity = true;// if you timer is running set true, if not false

        if (needBackgroundActivity)
        {
            if (_backgroundTask == null)
                _backgroundTask = new BackgroundTask(_logger.Value);

            _backgroundTask.Start();

            _logger.Value.Info("Background", "Task runned");
        }
    }

    private class BackgroundTask
    {
        private const string EmptySoundFileName = "Sounds/empty";//wav file, I use 4 sec long file with no sound

        private TouchLogger _logger;

        private AVAudioPlayer _player;

        private NSTimer _debugTimer;

        public bool IsRunned { get; private set; }

        public BackgroundTask(TouchLogger logger)
        {
            _logger = logger;
        }

        public void Start()
        {
            IsRunned = true;

            if (_player != null && _player.Playing)
            {
                Stop();
            }

            var bundle = NSBundle.MainBundle.PathForResource(EmptySoundFileName, "wav");
            var sound = new NSUrl(bundle);


            _player = AVAudioPlayer.FromUrl(sound);
            _player.NumberOfLoops = -1;
            _player.Volume = 0.1f;
            _player.PrepareToPlay();
            _player.Play();
            startDebugTimer();
        }

        public void Stop()
        {
            IsRunned = false;

            if (_player != null && _player.Playing)
            {
                _player.Stop();
                _player.Dispose();
                _player = null;
            }
            stopTimer(ref _debugTimer);
        }

        private void startDebugTimer()
        {
            initAndStartTimer(ref _debugTimer, 5,
                () => _logger.Value.Info("Background", "Background is fine!"));
        }

        private void initAndStartTimer(ref NSTimer timer, int intervalMin, Action action)
        {
            timer?.Invalidate();
            if (action != null)
                timer =
                    NSTimer.CreateRepeatingScheduledTimer(
                        TimeSpan.FromMinutes(intervalMin),
                        t => action());
        }



        private void stopTimer(ref NSTimer timer)
        {
            timer?.Invalidate();
            timer = null;
        }

    }

    #endregion      

TouchLogger-向控制台发送一些消息,以检查背景,您可以将其删除。与_debugTimer相同,它只平均每5分钟写入一次后台工作人员状态。

如果某件事告诉我,我很久以前就做过,所以可能错过了一些事情