使用 gps 定位系统服务依赖注入

Using gps location system services dependency injection

我希望使用 Xamarin 的依赖项注入获取特定于平台的位置详细信息,但 运行 问题。很可能是因为做错了。

这是我当前的设置:

nuMaps/Interfaces/ILocationService.cs

using Xamarin.Forms.Maps;

namespace nuMaps
{
    public interface ILocationService
    {
        void initLocationService();
        Position getCurrentPosition();
    }
}

nuMaps/nuMaps.Droid/Interfaces/LocationService.cs

using System;
using nuMaps;
using nuMaps.Droid;
using Xamarin.Forms.Maps;
using Android.App;
using Android.Gms.Common;
using Android.Gms.Common.Apis;
using Android.Gms.Location;
using Android.Locations;
using Android.Widget;

[assembly: Xamarin.Forms.Dependency (typeof (LocationService))]

namespace nuMaps.Droid
{
    public class LocationService : Java.Lang.Object, ILocationService, IGoogleApiClientConnectionCallbacks, IGoogleApiClientOnConnectionFailedListener, Android.Gms.Location.ILocationListener
    {
        readonly IGoogleApiClient _googleApiClient;
        readonly LocationRequest _locRequest;
        Position _currentPosition;
        Location _currentLocation;

        public LocationService()
        {
            Console.WriteLine ("LocationService constructor");
            _currentPosition = new Position (0, 0);

            _googleApiClient = new GoogleApiClientBuilder (Xamarin.Forms.Forms.Context)
                .AddApi (LocationServices.Api)
                .AddConnectionCallbacks (this)
                .AddOnConnectionFailedListener (this)
                .Build ();

            _locRequest = new LocationRequest ();
        }

        #region ILocationService implementation

        public void initLocationService()
        {
            _googleApiClient.Connect ();
        }

        public Position getCurrentPosition ()
        {
            if (_googleApiClient.IsConnected) {
                _currentLocation = LocationServices.FusedLocationApi.GetLastLocation (_googleApiClient);
                _currentPosition = new Position (_currentLocation.Latitude, _currentLocation.Longitude);
            }

            _googleApiClient.Disconnect ();

            return new Position (_currentLocation.Latitude, _currentLocation.Longitude);
        }

        #endregion
        public void OnLocationChanged(Location l)
        {
            Console.WriteLine ("OnLocationChanged");
            _currentLocation = l;
        }

        public void OnConnectionFailed (ConnectionResult result)
        {
            Console.WriteLine ("ConnectionFailed");
        }

        #region IGoogleApiClientConnectionCallbacks implementation
        public void OnConnected (Android.OS.Bundle connectionHint)
        {
            Console.WriteLine ("OnConnected");

            if (!_googleApiClient.IsConnected)
                LocationServices.FusedLocationApi.RequestLocationUpdates (_googleApiClient, _locRequest, this);

            _currentLocation = LocationServices.FusedLocationApi.GetLastLocation (_googleApiClient);
        }
        public void OnConnectionSuspended (int cause)
        {
            Console.WriteLine ("OnConnectionSuspended");
        }
        #endregion
    }
}

nuMaps/Views/MapPage.xaml.cs

中的用法
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using System;
using System.Diagnostics;

namespace nuMaps
{
    public partial class MapPage : ContentPage
    {

        public MapPage ()
        {
            InitializeComponent ();
            Position p = DependencyService.Get<ILocationService>().getCurrentPosition();
            MyMap.MoveToRegion (
                MapSpan.FromCenterAndRadius (
                    p, Distance.FromMiles (1)
                )
            );
        }
    }
}

nuMaps/Views/Loginpage.xaml.cs

using System;
using Xamarin.Forms;
using nuMaps;

namespace nuMaps
{
    public partial class LoginPage : ContentPage
    {
        public LoginPage ()
        {
            InitializeComponent ();

            /*
             * Init platform specific location service.
             * TODO: This *shouldn't* need to happen, but we don't get location information until
             * the OnConnected callback happens which is too slow to put in getCurrentLocation method.
             */

             DependencyService.Get<ILocationService>().initLocationService();
        }
    }
}

我认为问题出在您对 ILocationService 的实施中。

我会删除实现 activity(您为什么要使用 OnCreate?)并查看 http://developer.xamarin.com/guides/android/platform_features/maps_and_location/location/

我建议 Android 通过 google play api 获取 GPS 位置,这将需要实施 ILocationListenerIGoogleApiClientConnectionCallbacksIGoogleApiClientOnConnectionFailedListener.希望对您有所帮助!

编辑评论:

如果问题中的 LocationService 是最新的,我看不到您正在实施 IGoogleApiClientConnectionCallbacksILocationListener。可能是因为地图页面使用了gps,所以GetLastKnownLocation可以,因为最近获取了一个位置。

GPS 位置请求是一个异步操作 - IGoogleApiClientConnectionCallbacks 的方法之一是 OnConnected,您应该调用类似的方法:

LocationServices.FusedLocationApi.RequestLocationUpdates(googleApiClient, locationRequest, this);

这将主动请求位置更新,然后在返回位置更新时触发 OnLocationChanged(Location location)。这都是异步的,因此您可能需要在 LocationService 中公开这些事件并订阅它们。

您可以尝试 TinyIoC 而不是 Xamarin 依赖服务。它适用于特定于平台的实现,例如定位服务。

也许 Xamarin Dependency Service 可以用于这些类型的事情,但到目前为止我只将它用于自定义渲染器。对于更多基于服务的东西,我使用 TinyIoC。