【问题标题】:Location updates in Foreground Service前台服务中的位置更新
【发布时间】:2020-05-01 08:38:14
【问题描述】:

我正在尝试实现一个用于在后台导航用户的应用程序。我正在运行前台服务。但是对于RequestLocationUpdates,我有两个选择:

  1. 使用PendingIntent(通常这个用作背景)
  2. 使用LocationCallback

哪一个应该用于前台的位置更新?我想LocationCallback,但不确定。

提前致谢。

【问题讨论】:

    标签: android xamarin.android


    【解决方案1】:

    在前台服务中使用RequestLocationUpdates更新位置时,请实现Android.Locations.ILocationListener接口,实现OnLocationChanged方法。

    这是一些相关的代码

     [Service]
        public class LocationService : Service, ILocationListener
        {
            const int SERVICE_RUNNING_NOTIFICATION_ID = 123;
            const string NOTIFICATION_CHANNEL_ID = "com.company.app.channel";
    
            readonly string logTag = "LocationService";
            IBinder binder;
    
            // Set our location manager as the system location service
            protected LocationManager LocMgr = Application.Context.GetSystemService("location") as LocationManager;
    
            // ILocationListener is a way for the Service to subscribe for updates
            // from the System location Service
    
            public void OnLocationChanged(Android.Locations.Location location)
            {
                LocationChanged(this, new LocationChangedEventArgs(location));
    
                // This should be updating every time we request new location updates
                // both when teh app is in the background, and in the foreground
                Log.Debug(logTag, $"Latitude is {location.Latitude}");
                Log.Debug(logTag, $"Longitude is {location.Longitude}");
                Log.Debug(logTag, $"Altitude is {location.Altitude}");
                Log.Debug(logTag, $"Speed is {location.Speed}");
                Log.Debug(logTag, $"Accuracy is {location.Accuracy}");
                Log.Debug(logTag, $"Bearing is {location.Bearing}");
            }
    
            public void OnProviderDisabled(string provider)
            {
                ProviderDisabled(this, new ProviderDisabledEventArgs(provider));
            }
    
            public void OnProviderEnabled(string provider)
            {
                ProviderEnabled(this, new ProviderEnabledEventArgs(provider));
            }
    
            public void OnStatusChanged(string provider, Availability status, Bundle extras)
            {
                StatusChanged(this, new StatusChangedEventArgs(provider, status, extras));
            }
    
            public event EventHandler<LocationChangedEventArgs> LocationChanged = delegate { };
            public event EventHandler<ProviderDisabledEventArgs> ProviderDisabled = delegate { };
            public event EventHandler<ProviderEnabledEventArgs> ProviderEnabled = delegate { };
            public event EventHandler<StatusChangedEventArgs> StatusChanged = delegate { };
    
            public override void OnCreate()
            {
                base.OnCreate();
                Log.Debug(logTag, "OnCreate called in the Location Service");
            }
    
            // This gets called when StartService is called in our App class
            [Obsolete("deprecated in base class")]
            public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
            {
                Log.Debug(logTag, "LocationService started");
    
                // Check if device is running Android 8.0 or higher and call StartForeground() if so
                if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
                {
                    var notification = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
                                       .SetContentTitle(Resources.GetString(Resource.String.app_name))
                                       .SetContentText(Resources.GetString(Resource.String.notification_text))
                                       .SetSmallIcon(Resource.Drawable.notification_icon_background)
                                       .SetOngoing(true)
                                       .Build();
    
                    var notificationManager =
                        GetSystemService(NotificationService) as NotificationManager;
    
                    var chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "On-going Notification", NotificationImportance.Min);
    
                    notificationManager.CreateNotificationChannel(chan);
    
                    StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notification);
                }
    
                return StartCommandResult.Sticky;
            }
    
            // 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)
            {
                Log.Debug(logTag, "Client now bound to service");
    
                binder = new LocationServiceBinder(this);
                return binder;
            }
    
            // Handle location updates from the location manager
            public void StartLocationUpdates()
            {
                //we can set different location criteria based on requirements for our app -
                //for example, we might want to preserve power, or get extreme accuracy
                var locationCriteria = new Criteria();
    
                locationCriteria.Accuracy = Accuracy.NoRequirement;
                locationCriteria.PowerRequirement = Power.NoRequirement;
    
                // get provider: GPS, Network, etc.
                var locationProvider = LocMgr.GetBestProvider(locationCriteria, true);
                Log.Debug(logTag, string.Format("You are about to get location updates via {0}", locationProvider));
    
                // Get an initial fix on location
                LocMgr.RequestLocationUpdates(locationProvider, 2000, 0, this);
    
                Log.Debug(logTag, "Now sending location updates");
            }
    
            public override void OnDestroy()
            {
                base.OnDestroy();
                Log.Debug(logTag, "Service has been terminated");
    
                // Stop getting updates from the location manager:
                LocMgr.RemoveUpdates(this);
            }
        }
    }
    
    

    这是我的demo,大家可以参考一下。

    https://github.com/851265601/XAndroidLocation

    【讨论】:

    • 感谢您的回复。那么使用 PendingIntent 请求位置更新不应该在前台服务中使用?
    • 是的,PendingIntent 用于当前不需要执行的意图,将来可以执行此意图。如果你想在运行应用程序时不断请求位置,你应该使用前台服务(保持服务运行,在Android Q或更高版本中不会被GC杀死)并实现ILocationListener,当位置改变时,你将立即获取位置数据。
    • 如果回复有帮助,请不要忘记接受这个答案,它将帮助其他有类似问题的人。
    • 仅供参考,您提供的 Github 链接已损坏。问候。
    猜你喜欢
    • 2019-10-26
    • 2021-10-10
    • 1970-01-01
    • 1970-01-01
    • 2018-05-08
    • 1970-01-01
    • 2015-07-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多