繁体   English   中英

在OnNavigatedToAsync中实例化LocationService导致应用挂起

[英]Instantiating LocationService in OnNavigatedToAsync causes app to hang

我目前正在使用UWPTemplate10编写位置感知的MVVM应用程序。 作为此应用程序的一部分,我正在显示一个使用MapControl的地图页面,这需要显示用户的当前位置。

我正在尝试利用作为Template10框架一部分的LocationService (尽管该服务当前未包含在NuGet包中)。 遇到的问题是,由于此MSDN文章中提到的约束,即,我无法调用此服务来获取页面的OnNavigatedToAsync方法中用户的当前位置:

访问用户的位置之前,请调用RequestAccessAsync。 那时,您的应用必须位于前台,并且必须从UI线程调用RequestAccessAsync。 在用户向您的应用授予其位置权限之前,您的应用无法访问位置数据。

这是因为向用户显示了一个对话框,询问允许使用设备位置的权限-但由于我们不在UI线程上,因此该应用程序仅挂起。

页面完成加载并准备就绪后,是否可以调用另一种方法(将调用LocationService )? 我尝试从页面的Loaded事件中挂入命令调用,但是在那里也发生了相同的问题。

我正在尝试利用作为Template10框架一部分的LocationService(尽管该服务当前未包含在NuGet包中)。

您这个LocationService是什么意思? 我找不到与此有关的任何文档。 我只是在您提供的文档中使用了Geolocator来测试您的问题,所以我无法复制它。

这是因为向用户显示了一个对话框,询问允许使用设备位置的权限-但由于我们不在UI线程上,因此该应用程序仅挂起。

不,据说在访问用户位置之前必须先调用RequestAccessAsync方法,并且必须从UI线程中调用,如果在OnNavigatedToAsync调用此RequestAccessAsync方法,则从UI线程中调用该应用程序将不会挂起。

这是我的示例,我创建了一个空的汉堡模板10项目,并在“详细信息”页面中:

首先添加4 TextBlock以在xaml中显示状态和位置:

<!--  content  -->
<ScrollViewer Padding="12,8,0,0" RelativePanel.AlignBottomWithPanel="True"
              RelativePanel.AlignLeftWithPanel="True"
              RelativePanel.AlignRightWithPanel="True"
              RelativePanel.Below="pageHeader"
              VerticalScrollBarVisibility="Auto">
    <StackPanel>
        <TextBlock Style="{StaticResource TitleTextBlockStyle}" Text="You passed:" />
        <TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{x:Bind ViewModel.Value, Mode=OneWay, FallbackValue=DesigntimeValue}" />
        <TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{x:Bind ViewModel.Status,Mode=OneWay}" />
        <TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{x:Bind ViewModel.Latitude, Mode=OneWay}" />
        <TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{x:Bind ViewModel.Longitude, Mode=OneWay}" />
        <TextBlock Style="{StaticResource SubtitleTextBlockStyle}" Text="{x:Bind ViewModel.Accuracy, Mode=OneWay}" />
    </StackPanel>
</ScrollViewer>

ViewModel中的部分代码:

public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary<string, object> suspensionState)
{
    Value = (suspensionState.ContainsKey(nameof(Value))) ? suspensionState[nameof(Value)]?.ToString() : parameter?.ToString();

    StartTracking();

    await Task.CompletedTask;
}

private async void StartTracking()
{
    // Request permission to access location
    var accessStatus = await Geolocator.RequestAccessAsync();

    switch (accessStatus)
    {
        case GeolocationAccessStatus.Allowed:
            _cts = new CancellationTokenSource();
            CancellationToken token = _cts.Token;
            _geolocator = new Geolocator { DesiredAccuracyInMeters = _desireAccuracyInMetersValue };
            Geoposition pos = await _geolocator.GetGeopositionAsync().AsTask(token);
            UpdateLocationData(pos);
            // Subscribe to PositionChanged event to get updated tracking positions
            _geolocator.PositionChanged += OnPositionChanged;

            // Subscribe to StatusChanged event to get updates of location status changes
            _geolocator.StatusChanged += OnStatusChanged;
            break;

        case GeolocationAccessStatus.Denied:
            break;

        case GeolocationAccessStatus.Unspecified:
            break;
    }
}

其他代码可以参考官方地理位置示例

页面加载完成并准备就绪后,是否可以调用另一种方法(将调用LocationService)?

我认为问题在于您需要检查导致应用程序挂起的确切原因。 如果是LocationService的问题,可以在评论中发布该服务的文档吗?

更新:

如果您阅读此LocationService的源代码,并且使用代码var locationService = new LocationService();var pos = locationService.Position; ,则可以找到它将Geolocation API打包到一个服务中var locationService = new LocationService();var pos = locationService.Position; ,那么StartTracking()方法中的大多数代码都是无用的,它们只是创建了另一个Geolocator ,并尝试获取位置,并在位置再次更改时获取通知,就像服务一样。 但是仍然需要RequestAccessAsync ,并且必须在新建LocationService实例之前调用RequestAccessAsync ,因此可以这样编写代码:

public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary<string, object> suspensionState)
{
    Value = (suspensionState.ContainsKey(nameof(Value))) ? suspensionState[nameof(Value)]?.ToString() : parameter?.ToString();
    var accessStatus = await Geolocator.RequestAccessAsync();
    var locationService = new LocationService();
    var pos = locationService.Position;
    //StartTracking();
    await Task.CompletedTask;
}

刚刚测试,效果很好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM