使用WP7的Location Service 和Google Maps API Web Services获取具体地址

  Microsoft 地理位置服务允许开发者为 Windows Phone 创建位置感知应用程序。该服务从获得来源(如 GPS、Wi-Fi 和蜂窝)获取位置数据。它可以使用一个或多个来源推导出 Windows Phone 的位置,从而根据应用程序的需要平衡性能和电能利用。通过事件驱动的托管代码接口向应用程序公开位置。

      ◇定位服务体系结构:

      第一层由 Windows Phone 设备中的硬件组成。这包括 GPS 接收器、Wi-Fi 和蜂窝收音机。这些可以全部充当精度和能耗级别各不相同的位置数据的提供程序;

      在硬件的上面是本机代码层。该层直接与可用的位置数据来源通信并决定使用哪个来源,根据数据的可用性以及应用程序指定的性能要求确定设备的位置。本机代码层还借助 Microsoft 托管的 Web 服务与 Internet 通信,以从数据库查找与位置有关的信息;

      定位服务的顶层是托管接口,通过 Windows Phone SDK 附带的 DLL 公开。应用程序使用该接口启动和停止定位服务,设置应用程序所需的精度级别以及从本机代码层(当它变为可用时)接收位置数据。

      ◇创建使用Location Service程序的最佳实践:

      创建位置感知应用程序时,开发人员必须平衡应用程序的以下两个要求:具有精确位置数据;耗电量最小。在移动设备上,这两个应用程序要求是反比关系。生成不太精确位置信息的硬件(如 Wi-Fi 和蜂窝收音机)使用的电量要比 GPS 接收器(通常,可以获得更精确的位置数据)使用的电量小。设计应用程序时,要遵循两个基本原则。

      为位置数据选择适当的精度级别:尽管定位服务使用多个位置信息来源,但是在任何给定的时间任何来源都可能会不可用(例如,无法访问 GPS 卫星或基站),本机代码层负责计算可用数据并选择最佳来源集。您的应用程序所需要做的就是在高精度或默认的电量优化设置之间进行选择。可以在初始化主定位服务类 GeoCoordinateWatcher 时设置该值。

GeoCoordinateWatcher watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);

      设置合理的移动阈值:由于移动设备中的 GPS 硬件没有天线,因此传感器通常设计为非常敏感。这种灵敏度可能会导致信号中有少量来自表面反射以及其他环境影响的噪音。主定位服务类 GeoCoordinateWatcher 显示 MovementThreshold 属性。该属性指定在引发 PositionChanged 事件之前必须进行的位置方面的最小更改。如果您将 MovementThreshold 属性设置为一个非常低的值,则可能会导致您的应用程序接收实际上是由信号噪音所导致的事件。为了平滑信号以便仅表示位置中的重大更改,请将 MovementThreshold 属性设置为至少 20 米。这也会使您应用程序的耗电量降低。将移动阈值设置为 0 米将导致频繁引发事件,一秒钟一个事件。该设置对于导航应用程序可能非常有用。

      下面给出一个例子演示如何从 Windows Phone 的定位服务获取数据:

MainPage.xaml

<phone:PhoneApplicationPage 
    x:Class="LocationTest2.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">

    <!--LayoutRoot 是包含所有页面内容的根网格-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel 包含应用程序的名称和页标题-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="我的应用程序" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="页面名称" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <!--ContentPanel - 在此处放置其他内容-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Button Content="开始" Height="72" HorizontalAlignment="Left" Margin="12,352,0,0" Name="button1" VerticalAlignment="Top" Width="160" Click="button1_Click" />
            <Button Content="结束" Height="72" HorizontalAlignment="Left" Margin="260,352,0,0" Name="button2" VerticalAlignment="Top" Width="160" />
            <TextBlock Height="30" HorizontalAlignment="Left" Margin="89,34,0,0" Name="textBlock1" Text="经度" VerticalAlignment="Top" />
            <TextBlock Height="30" HorizontalAlignment="Left" Margin="89,112,0,0" Name="textBlock2" Text="纬度" VerticalAlignment="Top" />
            <TextBlock Height="30" HorizontalAlignment="Left" Margin="89,190,0,0" Name="textBlock3" Text="城市" VerticalAlignment="Top" />
        </Grid>
    </Grid>
 
    <!--演示 ApplicationBar 用法的示例代码-->
    <!--<phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="按钮 1"/>
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="按钮 2"/>
            <shell:ApplicationBar.MenuItems>
                <shell:ApplicationBarMenuItem Text="菜单项 1"/>
                <shell:ApplicationBarMenuItem Text="菜单项 2"/>
            </shell:ApplicationBar.MenuItems>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>-->

</phone:PhoneApplicationPage>

  MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

namespace LocationTest2
{
    public partial class MainPage : PhoneApplicationPage
    {
        private Location location;
        // 构造函数
        public MainPage()
        {
            InitializeComponent();
            location = new Location();
            location.GetPositionCompleted += new Location.PositionChangedHandle(location_GetPositionCompleted);
            location.GetStatus += new Location.LocationStatusHandle(location_GetStatus);
            location.GetCityName += new Location.CityHandle(location_GetCityName);
        }

        void location_GetCityName(string CityName)
        {
            textBlock3.Text = CityName;
        }

        void location_GetStatus(string message, bool result)
        {
            this.PageTitle.Text = location.text;
        }

        void location_GetPositionCompleted(object sender, string[] locations)
        {
            textBlock1.Text = location.locations[0];
            textBlock2.Text = location.locations[1];
            location.GetCity(locations);
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            location.GetLocation();
        }
    }
}

Google Maps API Web Services

1. 什么是网络服务?

Google Maps API 提供这些网络服务作为从外部服务中请求 Google Maps API 数据以及在您的地图应用程序中使用它们的接口。这些网络服务使用特定网址的 HTTP 请求并将网址参数作为参数提供给服务。一般来讲,这些服务会在 HTTP 请求中以 JSON 或 XML 的形式传回数据,供您的应用程序进行解析和/或处理。

一个典型的网络服务请求通常采用以下形式:

http://maps.google.com/maps/api/service/output?parameters

其中 service 表示所请求的特定服务,output 表示响应格式(通常为 json 或 xml)。

 

2.地址解析与反地址解析

地址解析是将地址(如“1600 Amphitheatre Parkway, Mountain View, CA”)转换为地理坐标(如纬度 37.423021 和经度 -122.083739)的过程,您可以根据转换得到的坐标放置标记或定位地图。Google Geocoding API 可让您通过 HTTP 请求直接访问地址解析器。此外,该服务还可让您执行反向操作(将坐标转换为地址),此过程称为“反向地址解析”(地址查询)

 

3. 地址查询(反向地址解析)请求

Google Geocoding API 请求必须采用以下形式:

http://maps.google.com/maps/api/geocode/output?parameters

其中,output 可以是以下值之一:

  • json(建议)表示以 JavaScript 对象表示法 (JSON) 的形式输出
  • xml 表示以 XML 的形式输出

有些参数是必需的,有些是可选的。根据网址的标准,所有参数均使用字符 & (&) 分隔。下面枚举了这些参数及其可能的值。

Google Geocoding API 使用以下网址参数定义地址查询请求:

  • latlng(必需)- 您希望获取的、距离最近的、可人工读取地址的纬度/经度文本值。
  • bounds(可选)- 要在其中更显著地偏移地址解析结果的可视区域的边框。
  • region(可选)- 区域代码,指定为 ccTLD(“顶级域”)双字符值。
  • language(可选)- 传回结果时所使用的语言。请注意,我们会经常更新支持的语言,因此该列表可能并不详尽。如果未提供 language,地址解析器将尝试尽可能使用发送请求的区域的本地语言。
  • sensor(必需)- 指示地址解析请求是否来自装有位置传感器的设备。该值必须为 true 或 false

注意:bounds 和 region 参数只会影响地址解析器返回的结果,但不能对其进行完全限制。

 

实例:创建查询坐标(40.053,116.287)的地址信息的请求,要求以json格式输出响应,语言为简体中文(zh-CN)。

http://maps.google.com/maps/api/geocode/json?latlng=39.910093,116.403945&language=zh-CN&sensor=false
注意:经纬度书写的顺序为(纬度,经度)
下面是Location类的具体代码 包含Location Service和Google API
Location.cs
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Device.Location;
using System.Windows.Threading;
using Newtonsoft.Json.Linq;

namespace LocationTest2
{
    public class Location
    {
        GeoCoordinateWatcher watcher;
        public string text;
        public string[] locations;

        public Location()
        {
            locations=new string[2];
        }
        public void GetLocation()
        {
            if (watcher == null)
            {
                watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);
                watcher.MovementThreshold = 20;
                watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);
                watcher.StatusChanged += new EventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged);
                watcher.Start();
            }
        }

        void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
        {
            switch (e.Status)
            {
                case GeoPositionStatus.Initializing:
                    // The Location Service is initializing.
                    // Disable the Start Location button.                    
                    break;
                case GeoPositionStatus.NoData:
                    text = "location data is not available.";
                    break;
                case GeoPositionStatus.Ready:
                    text = "location data is available";
                    break;
                case GeoPositionStatus.Disabled:
                    if (watcher.Permission == GeoPositionPermission.Denied)
                    {
                        // The user has disabled the Location Service on their device.
                        text = "you have this application access to location.";
                    }
                    else
                    {
                        text = "location is not functioning on this device";
                    }
                    break;
            }
            if (GetStatus!=null)
            {
                GetStatus(text, true);
            }
        }

        void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() =>
                                                          {
                                                              locations[0] =
                                                                  e.Position.Location.Longitude.ToString("0.000");
                                                              locations[1] =
                                                                  e.Position.Location.Latitude.ToString("0.000");
                                                              if (GetPositionCompleted!=null)
                                                              {
                                                                  GetPositionCompleted(this, locations);
                                                              }
                                                          });
        }

        public void GetCity(string[] locations)
        {
            string uri =
                string.Format("http://maps.google.com/maps/api/geocode/json?latlng={0},{1}&language=zh-CN&sensor=false",
                              locations[1], locations[0]);
            WebClient cilent = new WebClient();
            cilent.DownloadStringAsync(new Uri(uri,UriKind.Absolute));
            cilent.DownloadStringCompleted += new DownloadStringCompletedEventHandler(cilent_DownloadStringCompleted);
        }

        void cilent_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            JObject json = JObject.Parse(e.Result);
            string cityName = (string)json["results"][0]["address_components"][1]["short_name"];
            if (GetCityName!=null)
            {
                GetCityName(cityName);
            }
        }
        public void WatcherStop()
        {
            watcher.Stop();
        }

        public delegate void PositionChangedHandle(object sender, string[] locations);
        public delegate void LocationStatusHandle(string message, bool result);
        public delegate void CityHandle(string CityName);

        public event PositionChangedHandle GetPositionCompleted;
        public event LocationStatusHandle GetStatus;
        public event CityHandle GetCityName;
    }
}

  

返回的json数据为
{
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "后厂村路",
               "short_name" : "后厂村路",
               "types" : [ "route" ]
            },
            {
               "long_name" : "海淀区",
               "short_name" : "海淀区",
               "types" : [ "sublocality", "political" ]
            },
            {
               "long_name" : "北京",
               "short_name" : "北京",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "北京市",
               "short_name" : "北京市",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "中国",
               "short_name" : "CN",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "中国北京市海淀区后厂村路",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 40.05266650,
                  "lng" : 116.29035070
               },
               "southwest" : {
                  "lat" : 40.05163950,
                  "lng" : 116.28483320
               }
            },
            "location" : {
               "lat" : 40.05213570,
               "lng" : 116.28759750
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 40.05350198029150,
                  "lng" : 116.29035070
               },
               "southwest" : {
                  "lat" : 40.05080401970851,
                  "lng" : 116.28483320
               }
            }
         },
         "types" : [ "route" ]
      },
      {
         "address_components" : [
            {
               "long_name" : "海淀区",
               "short_name" : "海淀区",
               "types" : [ "sublocality", "political" ]
            },
            {
               "long_name" : "北京",
               "short_name" : "北京",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "北京市",
               "short_name" : "北京市",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "中国",
               "short_name" : "CN",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "中国北京市海淀区",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 40.16098550,
                  "lng" : 116.39509270
               },
               "southwest" : {
                  "lat" : 39.88664330,
                  "lng" : 116.04883810
               }
            },
            "location" : {
               "lat" : 39.959710,
               "lng" : 116.2980120
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 40.16098550,
                  "lng" : 116.39509270
               },
               "southwest" : {
                  "lat" : 39.88664330,
                  "lng" : 116.04883810
               }
            }
         },
         "types" : [ "sublocality", "political" ]
      },
      {
         "address_components" : [
            {
               "long_name" : "北京市",
               "short_name" : "北京市",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "中国",
               "short_name" : "CN",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "中国北京市",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 41.06081580,
                  "lng" : 117.51462510
               },
               "southwest" : {
                  "lat" : 39.44275810,
                  "lng" : 115.42341150
               }
            },
            "location" : {
               "lat" : 39.9042140,
               "lng" : 116.4074130
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 41.06081580,
                  "lng" : 117.51462510
               },
               "southwest" : {
                  "lat" : 39.44275810,
                  "lng" : 115.42341150
               }
            }
         },
         "types" : [ "administrative_area_level_1", "political" ]
      },
      {
         "address_components" : [
            {
               "long_name" : "北京",
               "short_name" : "北京",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "北京市",
               "short_name" : "北京市",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "中国",
               "short_name" : "CN",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "中国北京市",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 41.06081580,
                  "lng" : 117.51462510
               },
               "southwest" : {
                  "lat" : 39.44275810,
                  "lng" : 115.42341150
               }
            },
            "location" : {
               "lat" : 39.9042140,
               "lng" : 116.4074130
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 40.21649620,
                  "lng" : 116.78298350
               },
               "southwest" : {
                  "lat" : 39.66127140,
                  "lng" : 116.01193430
               }
            }
         },
         "types" : [ "locality", "political" ]
      },
      {
         "address_components" : [
            {
               "long_name" : "中国",
               "short_name" : "CN",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "中国",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 53.56097399999999,
                  "lng" : 134.772810
               },
               "southwest" : {
                  "lat" : 18.15352160,
                  "lng" : 73.49941369999999
               }
            },
            "location" : {
               "lat" : 35.861660,
               "lng" : 104.1953970
            },
            "location_type" : "APPROXIMATE",
            "viewport" : {
               "northeast" : {
                  "lat" : 53.56097399999999,
                  "lng" : 134.772810
               },
               "southwest" : {
                  "lat" : 18.15352160,
                  "lng" : 73.49941369999999
               }
            }
         },
         "types" : [ "country", "political" ]
      }
   ],
   "status" : "OK"
}

  运行结果

PS:模拟器是无法定位准确的经纬度的 这些数据是我在手机上运行获取经纬度后手动加上的

 

 

posted on 2012-06-28 13:18  MessageDream  阅读(531)  评论(0)    收藏  举报

导航