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

时间:2017-05-22 00:54:31

标签: android xamarin service xamarin.android locationmanager

我一直非常成功地开始服务。但是在这项服务中,我有一位位置经理,我开始从gps提供商那里获得位置更新。

位置管理器成功将回调发送到我的ILocationListener。 但是第二次手机进入睡眠状态(((PowerManager)GetSystemService(Context.PowerService))。IsScreenOn == false)

我在后台成功处理了一个位置更新,但之后... 没有更多的位置更新,即将进行回调。即使我使用startForeground()方法在前台显式启动它。

为什么会这样?我做错了吗?

这是我开始服务的地方(在MainActivity.cs中,来自Xamarin.Form ContentPage的trought依赖注入)

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

}

1 个答案:

答案 0 :(得分:0)

我设法找到一种方法来欺骗用户手机处于睡眠状态,屏幕仍被检测为屏幕关闭,基本上我在后台工作时使用了唤醒锁

这是我使用的方法:

 private async void PerformBackgroundWork(object state)
    {
        //BackgroundWork
       await Task.Run(() =>
        {
            try
            {
                if (Track.isRecording)
                {
                    try
                    {
                        backgroundInitialiser.Change(50000, 50000);

                        if (UpdatedLocation != null)
                            UpdateGPS(UpdatedLocation);
                        else
                        {
                            //REQUEST CUSTOM UPDATE , USE WAKE LOCK
                            PowerManager pm = ((PowerManager)GetSystemService(Context.PowerService));
                            PowerManager.WakeLock wl = pm.NewWakeLock(WakeLockFlags.ScreenDim,"00");

                            wl.Acquire();
                            Criteria c = new Criteria()
                            {
                                Accuracy = Accuracy.NoRequirement,
                                PowerRequirement = Power.NoRequirement
                            };
                            LocMgr.RequestSingleUpdate(c, this,this.MainLooper);
                            wl.Release();
                            pm = null;
                            wl=null;
                            c = null;
                            GC.Collect();
                        }

                    }
                    catch (System.Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine(ex.ToString());
                    }
                    finally
                    {
                        backgroundInitialiser.Change(recordingDelay, recordingDelay);
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        });
    }