防止位置管理器在手机进入睡眠状态时停止位置更新 Xamarin.Android

问题描述 投票:0回答:1

我非常成功地启动了一项服务。但在这个服务中,我有一个位置管理器,我开始从 GPS 提供商获取位置更新。

位置管理器成功向我的 ILocationListener 发送回调。 但下一秒手机就进入睡眠状态了

(((PowerManager)GetSystemService(Context.PowerService)).IsScreenOn==false)

我在后台成功处理了一次位置更新,但在那之后...... 通过回调不再有位置更新。即使我使用 startForeground() 方法在前台显式启动它。

为什么会有这样的表现?我是不是做错了什么?

这是我启动服务的地方(在 MainActivity.cs 中,通过从 Xamarin.Form ContentPage 进行依赖项注入)

public event EventHandler<ServiceConnectedEventArgs> LocationServiceConnected = delegate { };
    protected RecordingServiceConnection recordingServiceConnection;

    private static Intent locationServiceIntent = null;
    /// <summary>
    /// Start Track Recording Service
    /// </summary>
    /// <param name="toStart">object to use through service</param>
    public void Start(object toStart)
    {
        // starting a service like this is blocking, so we want to do it on a background thread
        new Task(() =>
        {
            // start our main service
            Android.App.Application.Context.StartService(new Intent(Android.App.Application.Context,
                typeof(RecordingService)));

            // create a new service connection so we can get a binder to the service
            this.recordingServiceConnection = new RecordingServiceConnection(null);

            // this event will fire when the Service connection in the OnServiceConnected call 
            this.recordingServiceConnection.ServiceConnected += (object sender, ServiceConnectedEventArgs e) =>
            {
                // we will use this event to notify MainActivity when to start updating the UI
                this.LocationServiceConnected(this, e);
            };

            // bind our service (Android goes and finds the running service by type, and puts a reference
            // on the binder to that service)
            // The Intent tells the OS where to find our Service (the Context) and the Type of Service
            // we're looking for (RecordingService)
            locationServiceIntent = new Intent(Android.App.Application.Context, typeof(RecordingService));
            //  Log.Debug(logTag, "Calling service binding");

            // Finally, we can bind to the Service using our Intent and the ServiceConnection we
            // created in a previous step.
            Android.App.Application.Context.BindService(locationServiceIntent, recordingServiceConnection,
                Bind.AutoCreate);

        }).Start();
    }

现在所说的服务:

    [Service]
    public class RecordingService : Android.App.Service, ILocationListener
    {

        #region Events
        public event EventHandler<LocationChangedEventArgs> LocationChanged = delegate { };
        public event EventHandler<ProviderDisabledEventArgs> ProviderDisabled = delegate { };
        public event EventHandler<ProviderEnabledEventArgs> ProviderEnabled = delegate { };
        public event EventHandler<StatusChangedEventArgs> StatusChanged = delegate { };
        #endregion

        #region locals
        //new location
        private Location UpdatedLocation = null;

        IBinder binder;

        //Backgrounding
        Timer backgroundInitialiser;
        long recordingDelay = 3000; // TODO SET IN SETTINGS

        private bool IsGpsEnabled = false;
        #endregion
        //
        // Set our location manager as the system location service
        protected LocationManager LocMgr = null;
        //
        private static PendingIntent pendingIntent = null;
        #region Service
        public override void OnCreate()
        {
            base.OnCreate();

            try
            {

                Intent notificationIntent = new Intent(this, typeof(RecordingService));
                pendingIntent = PendingIntent.GetActivity(this, 0,
                    notificationIntent, 0);
                var notification = new Notification.Builder(this)
                           .SetContentTitle("App")
                           .SetContentText("App is running")
                           .SetSmallIcon(Resource.Drawable.icon)
                           .SetOngoing(true)
                           .SetContentIntent(pendingIntent)
                           .Build();

                // Enlist this instance of the service as a foreground service
                StartForeground(999, notification);
                System.Diagnostics.Debug.WriteLine("OnCreate called in the Location Service");
            }
            catch(Exception ex)
            {
                throw;
            }
        }

        // This gets called when StartService is called in our App class
        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
        {
           System.Diagnostics.Debug.WriteLine("LocationService started");
            // start a task here
            new Task(async() =>
            {
            }).Start();

            InitializeBackgroundWork();

            return StartCommandResult.Sticky;
        }
        public override void OnDestroy()
        {
            base.OnDestroy();
           System.Diagnostics.Debug.WriteLine( "Service has been terminated");
        }
        #endregion

        private async void DoSomethinOnChange(object sender, LocationChangedEventArgs e)
        {
            UpdatedLocation = null;
            try
            {
               await Task.Run(async () =>
                {
                    try
                    {
                        Location location = e.Location;
                        var w= ((PowerManager)GetSystemService(Context.PowerService)).IsScreenOn;
                        if (w)
                        {
                            System.Diagnostics.Debug.WriteLine("INTO");
                        }
                        else
                            System.Diagnostics.Debug.WriteLine("NOT IN");


                    }
                    catch (Exception exception)
                    {
                        Console.WriteLine(exception);
                        throw;
                    }
                });
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
                throw;
            }
        }

        #region BackgroundWork

        private Thread backgroundWorkThread = null;
        /// <summary>
        /// Start the ForeGrounding
        /// </summary>
        private void InitializeBackgroundWork()
        {
            try
            {
                Thread backgroundWorkThread = new Thread(() =>
                {
                    if (backgroundInitialiser == null)
                    {
                        var autoEvent = new AutoResetEvent(false);
                        backgroundInitialiser = new Timer(new TimerCallback(PerformBackgroundWork), autoEvent, recordingDelay, recordingDelay);
                        GC.Collect();
                    }
                    else
                        backgroundInitialiser.Change(recordingDelay, recordingDelay);

                    StartLocationUpdates();
                });
                backgroundWorkThread.Start();
            }
            catch (System.Exception ex)
            {
               System.Diagnostics.Debug.WriteLine(ex.ToString());
            }

        }

        /// <summary>
        /// Performing foregrounding
        /// </summary>
        /// <param name="state"></param>
        private async void PerformBackgroundWork(object state)
        {
            //BackgroundWork
           await Task.Run(() =>
            {
                try
                {
                    if (Track.isRecording)
                    {
                        try
                        {
                            backgroundInitialiser.Change(50000, 50000);

                            if (UpdatedLocation != null)
                                UpdateGPS(UpdatedLocation);
                            //REQUEST CUSTOM UPDATE , USE WAKE LOCK
                        }
                        catch (System.Exception ex)
                        {
                            System.Diagnostics.Debug.WriteLine(ex.ToString());
                        }
                        finally
                        {
                            backgroundInitialiser.Change(recordingDelay, recordingDelay);
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            });
        }
        #endregion

        #region Binder
        // This gets called once, the first time any client bind to the Service
        // and returns an instance of the LocationServiceBinder. All future clients will
        // reuse the same instance of the binder
        public override IBinder OnBind(Intent intent)
        {
           System.Diagnostics.Debug.WriteLine( "Client now bound to service");

            binder = new RecordingServiceBinder(this);
            return binder;
        }
        #endregion

        // Handle location updates from the location manager, if Network is enabled we take network
        public void StartLocationUpdates()
        {
            try
            {
                if(!Looper.MainLooper.IsCurrentThread)
                     Looper.Prepare();
                if (LocMgr == null)
                {
                    LocMgr = GetSystemService(LocationService) as LocationManager;

                    IsGpsEnabled = LocMgr.IsProviderEnabled(LocationManager.GpsProvider);
                    // IsNetworkEnabled = LocMgr.IsProviderEnabled(LocationManager.NetworkProvider);
                    if (IsGpsEnabled)
                    {
                        LocMgr.RequestLocationUpdates(LocationManager.GpsProvider, 3000, 0, this);
                    }
                    LocationChanged += DoSomethinOnChange; // assign delegate to write to file
                }
                System.Diagnostics.Debug.WriteLine("Now sending location updates");
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }
        /// <summary>
        /// Gps Location Updated
        /// </summary>
        /// <param name="location"></param>
       async void UpdateGPS(Location location)
        {
            UpdatedLocation = null;
            await Task.Run(() =>
            {
                try
                {

                    this.LocationChanged(this, new LocationChangedEventArgs(location));

                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.ToString());
                }

            });
        }


        #region ILocationListener
        public void OnLocationChanged(Location location)
        {
            UpdatedLocation = location;
        }
        public void OnProviderDisabled(string provider)
        {
            this.ProviderDisabled(this, new ProviderDisabledEventArgs(provider));
        }

        public void OnProviderEnabled(string provider)
        {
            this.ProviderEnabled(this, new ProviderEnabledEventArgs(provider));
        }

        public void OnStatusChanged(string provider, Availability status, Bundle extras)
        {
            this.StatusChanged(this, new StatusChangedEventArgs(provider, status, extras));
        }
        #endregion

        public void StopDoingSomeWork()
        {
            backgroundWorkThread?.Abort();
            LocationChanged -= DoSomethinOnChange;
            LocMgr.Dispose();
            StopForeground(true);
            backgroundInitialiser.Dispose();
            StopSelf();
            GC.Collect();
        }

        protected override void Dispose(bool disposing)
        {
            backgroundInitialiser.Dispose();
            //backgroundWorkThread.Abort();
            GC.Collect();
        }
    }
}
android xamarin service xamarin.android locationmanager
1个回答
0
投票

编辑: 目标是将位置管理器注册为服务。 因此用户可以接受在后台运行的位置更新。 需要通知来保持服务运行。

见; 有关 Android 服务的 MSDocs

Xamarin 文档,后台任务

© www.soinside.com 2019 - 2024. All rights reserved.