使用Task.Run在Android上调用GetCurrentPositionAsync的异常

时间:2018-04-03 17:02:25

标签: android xamarin.forms xamarin.android geolocation

我正在尝试在Android上的Xamarin Forms中使用CrossGeolocator获取设备位置,但是下面的代码抛出了一条Exception,其中包含“无法在未调用Looper.prepare()的线程内创建处理程序”的消息。如何在不阻止UI线程的情况下调用GetPositionAsync?

定位服务

public async Task<Position> GetCurrentLocation(double desiredAccuracy = 100)
{
  Position position = null;
  try
  {
    var locator = CrossGeolocator.Current;
    locator.DesiredAccuracy = desiredAccuracy;

    var available = await locator.GetIsGeolocationAvailableAsync();
    var enabled = await locator.GetIsGeolocationEnabledAsync();
    if (!available || !enabled)
    {
      throw new Exception("Location Error.");
    }

    position = await locator.GetPositionAsync(TimeSpan.FromSeconds(20), null, true);
  }
  catch (Exception ex)
  {
    Device.BeginInvokeOnMainThread(() =>
    {
      App.Current.MainPage.DisplayAlert("Location Error", ex.Message, "Ok");
    });
  }

  return position;
}

Page.xaml.cs

private ILocationService _location;
private UserAccountViewModel _vm;
public UserAccountPage(UserAccountViewModel viewModel)
{
  InitializeComponent();
  BindingContext =_vm = viewModel;

  var _location = App.Container.Resolve<ILocationService>();

  Task.Run(async () => await _location.GetCurrentLocation())
    .ContinueWith(r =>
    {
      var loc = r.Result;
      _vm.UserAccount.Latitude= loc?.Latitude;
   }, TaskScheduler.FromCurrentSynchronizationContext());
}

如果我在Task.Run之外调用_location.GetCurrentLocation(),它会返回正确的值,但是我无法更新UI。

修改/更新: 我也可以从页面构造函数中调用以下代码,没有任何异常,所以问题必须是Xam.Plugin.Geolocator,我只是找不到关于这个场景的任何信息......

var dataService = App.Container.Resolve<IDataService>();
Task.Run(async () => await dataService.UserAccount.Localisations())
  .ContinueWith(result =>
  {
    _vm.UserAccount.FirstName = result.Result.Count().ToString();
  }, TaskScheduler.FromCurrentSynchronizationContext());

解决方法:我将代码移动到ViewModel并删除了Task.Run,​​然后从页面构造函数中调用了该函数,但我仍然想知道如何使用Task调用此代码。

public async Task UpdateLocation()
{
  var _location = App.Container.Resolve<ILocationService>();
  var loc = await _location.GetCurrentLocation();
  UserAccount.Latitude = loc?.Latitude;
}

1 个答案:

答案 0 :(得分:0)

您可以在 OnAppearing 方法中编写该代码。像,

protected override void OnAppearing()
{
  var _location = App.Container.Resolve<ILocationService>();

  Task.Run(async () => await _location.GetCurrentLocation())
  .ContinueWith(r =>
   {
      var loc = r.Result;
      _vm.UserAccount.Latitude= loc?.Latitude;
   }, TaskScheduler.FromCurrentSynchronizationContext());
}