未调用Xamarin Android位置更新

时间:2015-07-29 10:52:45

标签: android xamarin android-location

我正在尝试在活动期间记录位置但是我没有获得位置更新。我玩过最小刷新间隔以及距离间隔,但它仍然无法工作。我按照Xamarin的例子进行了位置更新,但我一直在敲打墙头,看看为什么位置更新无法正常工作!

public class ActivityManager : Java.Lang.Object, ILocationListener, ISensorEventListener
{
    private readonly LocationManager _locationManager;
    private readonly SensorManager _sensorManager;

    private readonly List<Location> _locationCache;
    private readonly List<SensorEvent> _sensorCache;

    private bool Continous { get; set; }

    public ActivityManager(LocationManager locationManager, SensorManager sensorManager)
    {
        _locationManager = locationManager;
        _sensorManager = sensorManager;

        _locationCache = new List<Location>();
        _sensorCache = new List<SensorEvent>();

        Continous = false;
    }

    public void StartTrackingLocation()
    {
        const string provider = LocationManager.GpsProvider;

        if (_locationManager.IsProviderEnabled(provider))
        {
            _locationManager.RequestLocationUpdates(provider, 0, 0, this);
        }
    }

    public void StartTrackingAccelerometer()
    {
        var mHandlerThread = new HandlerThread("sensorThread");
        mHandlerThread.Start();
        var handler = new Handler(mHandlerThread.Looper);
        _sensorManager.RegisterListener(this, _sensorManager.GetDefaultSensor(SensorType.Accelerometer),
            SensorDelay.Normal, handler);
    }

    public void StopTrackingLocation()
    {
        _locationManager.RemoveUpdates(this);
    }

    public void StopTrackingAccelerometer()
    {
        _sensorManager.UnregisterListener(this);
    }

    public void StartContinousTracking()
    {
        _locationCache.Clear();
        _sensorCache.Clear();

        Continous = true;
    }

    public void StopContinousTracking()
    {
        _locationCache.Clear();
        _sensorCache.Clear();

        Continous = false;
    }

    public void ExportLocationData(string path)
    {
        var kml = new Kml
        {
            Feature = new Placemark
            {
                Geometry = new LineString
                {
                    Coordinates = new CoordinateCollection(_locationCache.Select(l => new Vector {Latitude = l.Latitude, Longitude = l.Longitude}))
                }
            }
        };

        var kmlFile = KmlFile.Create(kml, true);

        using (var stream = File.OpenWrite(path))
        {
            kmlFile.Save(stream);
        }
    }

    public void ExportSensorData(string path)
    {
        var csv = new CsvWriter(new StreamWriter(path));

        csv.WriteField("AccX");
        csv.WriteField("AccY");
        csv.WriteField("AccZ");
        csv.NextRecord();

        foreach (var s in _sensorCache.ToList())
        {
            csv.WriteField(s.Values[0]);
            csv.WriteField(s.Values[1]);
            csv.WriteField(s.Values[2]);
            csv.NextRecord();
        }

        csv.Dispose();
    }

    public void OnLocationChanged(Location location)
    {
        _locationCache.Add(location);
        if (!Continous) _locationCache.RemoveAll(l => location.Time - l.Time > 120000);
    }

    public void OnSensorChanged(SensorEvent e)
    {
        _sensorCache.Add(e);
        if (!Continous) _sensorCache.RemoveAll(s => e.Timestamp - s.Timestamp > 120000000000);
    }

    public void OnProviderDisabled(string provider) { }

    public void OnProviderEnabled(string provider) { }

    public void OnStatusChanged(string provider, Availability status, Bundle extras) { }

    public void OnAccuracyChanged(Sensor sensor, SensorStatus accuracy) { }
}

提前致谢。

2 个答案:

答案 0 :(得分:0)

这是我用于Xamarin.Forms应用程序的Android元素的实现:

沟通班级

public class PlatformLocation : ILocation
{
    private readonly global::Android.Locations.LocationManager _locationManager;
    private readonly string[] _providers;
    private readonly TaskCompletionSource<PfgLocationInfo> _tcs;

    public PlatformLocation()
    {
        _locationManager = (global::Android.Locations.LocationManager)Application.Context.GetSystemService(Context.LocationService);
        _providers = _locationManager.GetProviders(false).Where(s => s != global::Android.Locations.LocationManager.PassiveProvider).ToArray();
        _tcs = new TaskCompletionSource<PfgLocationInfo>();
    }

    #region Private Methods

    Task<PfgLocationInfo> StartUpdatingLocation(int timeout = 0)
    {

        var lastKnownGpsLocation = _locationManager.GetLastKnownLocation("gps");
        if (lastKnownGpsLocation != null)
        {
            var pfgLocation = new PfgLocationInfo()
            { 
                Longitude = lastKnownGpsLocation.Longitude,
                Latitude = lastKnownGpsLocation.Latitude,
                Timestamp = DateTime.Now,
                Success = true,
                Status = PfgLocationStatus.Valid
            }; 
            _tcs.TrySetResult(pfgLocation);
            return _tcs.Task;
        }

        var lastKnownNetworkLocation = _locationManager.GetLastKnownLocation("network");
        if (lastKnownNetworkLocation != null)
        {
            var pfgLocation = new PfgLocationInfo()
            { 
                Longitude = lastKnownNetworkLocation.Longitude,
                Latitude = lastKnownNetworkLocation.Latitude,
                Timestamp = DateTime.Now,
                Success = true,
                Status = PfgLocationStatus.Valid
            }; 
            _tcs.TrySetResult(pfgLocation);
            return _tcs.Task;
        }

        LocationListener listener = null;
        listener = new LocationListener(
            _providers.Where(_locationManager.IsProviderEnabled),
            () =>
            {
                if (listener.Task.IsCanceled)
                {
                    _locationManager.RemoveUpdates(listener);       
                }
            },
            timeout
        );

        try
        {
            var looper = Looper.MyLooper() ?? Looper.MainLooper;
            var enabled = 0;

            for (var i = 0; i < _providers.Length; ++i)
            {
                if (_locationManager.IsProviderEnabled(_providers[i]))
                {
                    enabled++;
                }

                _locationManager.RequestLocationUpdates(_providers[i], 0, 0, listener, looper);
            }

            if (enabled == 0)
            {
                for (var i = 0; i < _providers.Length; ++i)
                {
                    _locationManager.RemoveUpdates(listener);
                }
                _tcs.TrySetResult(new PfgLocationInfo{ Timestamp = DateTime.Now, Status = PfgLocationStatus.Restricted, Success = false });
                return _tcs.Task;
            }

        }
        catch (TaskCanceledException tcex)
        {
            _tcs.TrySetResult(new PfgLocationInfo{ Timestamp = DateTime.Now, Status = PfgLocationStatus.Restricted, Success = false });
            return _tcs.Task;
        }
        catch (SecurityException)
        {
            _tcs.TrySetResult(new PfgLocationInfo{ Timestamp = DateTime.Now, Status = PfgLocationStatus.Restricted, Success = false });
            return _tcs.Task;
        }
        return listener.Task;
    }

    #endregion

    #region ILocation implementation

    public Task<PfgLocationInfo> GetLocationAsync()
    {
        return StartUpdatingLocation();
    }

    public Task<PfgLocationInfo> GetLocationAsync(int timeout)
    {
        return StartUpdatingLocation(timeout);
    }

    #endregion
}

ILocationListener实现:

public class LocationListener : Java.Lang.Object, ILocationListener
{
    private readonly HashSet<string> _activeProviders;
    private readonly TaskCompletionSource<PfgLocationInfo> _completionSource = new TaskCompletionSource<PfgLocationInfo>();
    private readonly Action _finishedCallback;
    private readonly Timer _timer;
    private readonly int _timeout;
    private readonly object _locationLock = new object();

    public Task<PfgLocationInfo> Task
    {
        get
        { 
            return _completionSource.Task;
        }
    }

    public LocationListener(IEnumerable<string> providers, Action finishedCallback, int timeout = -1)
    {
        _activeProviders = new HashSet<string>(providers);
        _finishedCallback = finishedCallback;
        if (timeout > 0)
        {
            _timeout = timeout;
            _timer = new Timer(TimesUp, null, _timeout * 1000, 0);
        }
    }

    #region Timeout Methods

    void TimesUp(object state)
    {
        lock (_locationLock)
        {
            if (_completionSource.TrySetCanceled() && _finishedCallback != null)
            {
                _finishedCallback();
            }
        }
        _timer.Dispose();
    }

    #endregion

    #region ILocationListener implementation

    public void OnLocationChanged(global::Android.Locations.Location location)
    {
        if (location != null)
        {
            Finish(location);
            return;
        }
    }

    public void OnProviderDisabled(string provider)
    {
        lock (_activeProviders)
        {
            if (_activeProviders.Remove(provider) && _activeProviders.Count == 0)
            {
                _completionSource.TrySetResult(new PfgLocationInfo{ Timestamp = DateTime.Now, Status = PfgLocationStatus.Restricted, Success = false });
            }
        }
    }

    public void OnProviderEnabled(string provider)
    {
        lock (_activeProviders)
            _activeProviders.Add(provider);
    }

    public void OnStatusChanged(string provider, Availability status, global::Android.OS.Bundle extras)
    {
        switch (status)
        {
            case Availability.Available:
                OnProviderEnabled(provider);
                break;

            case Availability.OutOfService:
                OnProviderDisabled(provider);
                break;
        }
    }

    #endregion

    #region Private Methods

    void Finish(global::Android.Locations.Location location)
    {

        var pfgLocationInfo = new PfgLocationInfo()
        { 
            Longitude = location.Longitude,
            Latitude = location.Latitude,
            Timestamp = DateTime.Now,
            Success = true,
            Status = PfgLocationStatus.Valid
        };
        _completionSource.TrySetResult(pfgLocationInfo);
    }

    #endregion
}

PfgLocationInfo只是一个用于保存结果的简单类

这完全符合要求,并且应该相对容易地转换为您的要求。

答案 1 :(得分:0)

事实证明这是有效但非常间歇性的。问题似乎是另一个正在运行的线程异步记录传感器数据正在排队操作,这些操作实际上淹没了位置更新。

删除传感器数据记录已启动,以允许位置更新通过。这对我来说似乎很奇怪,因为尽管传感器数据记录包含在他们自己的线程中,但这似乎发生了。