Xamarin google 映射 api

Xamarin google maps api

我正在使用下面的代码获取给定纬度和经度的城市名称。

但是当这一行是 运行:

时代码停止
var responseElement = XElement.Parse(response);

它停止响应并且没有抛出任何异常。

我猜可能是异步调用的问题。

任何人都可以帮我解决这个问题,或者建议使用 iOS SDK 的类似代码吗?谢谢

    private async Task<string> ReturnCity(string lat, string lon)
    {
        string city = "None";
        string baseUri = string.Format("http://maps.googleapis.com/maps/api/geocode/xml?latlng={0},{1}&sensor=false", lat, lon);
        HttpClient client = new HttpClient();
        var response = await client.GetStringAsync(baseUri);
        var responseElement = XElement.Parse(response);
        IEnumerable<XElement>statusElement = from st in responseElement.Elements("status") select st;
        if (statusElement.FirstOrDefault() != null)
        {
            string status = statusElement.FirstOrDefault().Value;
            if (status.ToLower() == "ok")
            {
                IEnumerable<XElement> resultElement = from rs in responseElement.Elements("result") select rs;
                if (resultElement.FirstOrDefault() != null)
                {
                    IEnumerable<XElement> addressElement = from ad in resultElement.FirstOrDefault().Elements("address_component") select ad;
                    foreach (XElement element in addressElement)
                    {
                        IEnumerable<XElement> typeElement = from te in element.Elements("type") select te;
                        string type = typeElement.FirstOrDefault().Value;
                        if(type=="locality")
                        {
                            IEnumerable<XElement> cityElement = from ln in element.Elements("long_name") select ln;
                            city = cityElement.FirstOrDefault().Value;
                            return city;
                            break;
                        }
                    }
                }
            }
        }
        return city;
    }

我通过调试器找到了响应值。它看起来像一个有效的 XML。有什么想法吗?

<?xml version="1.0" encoding="UTF-8"?>
<GeocodeResponse>
 <status>OK</status>
 <result>
  <type>airport</type>
  <type>transit_station</type>
  <type>establishment</type>
  <formatted_address>Lisbon Portela Airport (LIS), Alameda das Comunidades Portuguesas, 1700-111 Lisboa, Portugal</formatted_address>
  <address_component>
   <long_name>Lisbon Portela Airport</long_name>
   <short_name>Lisbon Portela Airport</short_name>
  </address_component>
  <address_component>
   <long_name>Alameda das Comunidades Portuguesas</long_name>
   <short_name>Alameda das Comunidades Portuguesas</short_name>
   <type>route</type>
  </address_component>
  <address_component>
   <long_name>Lisboa</long_name>
   <short_name>Lisboa</short_name>
   <type>locality</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Lisboa</long_name>
   <short_name>Lisboa</short_name>
   <type>administrative_area_level_1</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Portugal</long_name>
   <short_name>PT</short_name>
   <type>country</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>1700-111</long_name>
   <short_name>1700-111</short_name>
   <type>postal_code</type>
  </address_component>
  <geometry>
   <location>
    <lat>38.7755936</lat>
    <lng>-9.1353667</lng>
   </location>
   <location_type>APPROXIMATE</location_type>
   <viewport>
    <southwest>
     <lat>38.7623900</lat>
     <lng>-9.1475505</lng>
    </southwest>
    <northeast>
     <lat>38.7994779</lat>
     <lng>-9.1236185</lng>
    </northeast>
   </viewport>
   <bounds>
    <southwest>
     <lat>38.7623900</lat>
     <lng>-9.1475505</lng>
    </southwest>
    <northeast>
     <lat>38.7994779</lat>
     <lng>-9.1236185</lng>
    </northeast>
   </bounds>
  </geometry>
  <place_id>ChIJgwHZFkYyGQ0RRm0DWD6lZgo</place_id>
 </result>
 <result>
  <type>route</type>
  <formatted_address>Lisbon Portela Airport (LIS), Rua E, 1700-111 Lisboa, Portugal</formatted_address>
  <address_component>
   <long_name>Rua E</long_name>
   <short_name>R. E</short_name>
   <type>route</type>
  </address_component>
  <address_component>
   <long_name>Lisbon Portela Airport</long_name>
   <short_name>Lisbon Portela Airport</short_name>
  </address_component>
  <address_component>
   <long_name>Lisboa</long_name>
   <short_name>Lisboa</short_name>
   <type>locality</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Lisboa</long_name>
   <short_name>Lisboa</short_name>
   <type>administrative_area_level_1</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Portugal</long_name>
   <short_name>PT</short_name>
   <type>country</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>1700-111</long_name>
   <short_name>1700-111</short_name>
   <type>postal_code</type>
  </address_component>
  <address_component>
   <long_name>1700</long_name>
   <short_name>1700</short_name>
   <type>postal_code_prefix</type>
   <type>postal_code</type>
  </address_component>
  <geometry>
   <location>
    <lat>38.7757984</lat>
    <lng>-9.1304833</lng>
   </location>
   <location_type>GEOMETRIC_CENTER</location_type>
   <viewport>
    <southwest>
     <lat>38.7744765</lat>
     <lng>-9.1317496</lng>
    </southwest>
    <northeast>
     <lat>38.7771745</lat>
     <lng>-9.1290516</lng>
    </northeast>
   </viewport>
   <bounds>
    <southwest>
     <lat>38.7748799</lat>
     <lng>-9.1307609</lng>
    </southwest>
    <northeast>
     <lat>38.7767711</lat>
     <lng>-9.1300403</lng>
    </northeast>
   </bounds>
  </geometry>
  <place_id>ChIJjdzMckIyGQ0RvIXYZCCI82k</place_id>
 </result>
 <result>
  <type>locality</type>
  <type>political</type>
  <formatted_address>Lisbon, Portugal</formatted_address>
  <address_component>
   <long_name>Lisbon</long_name>
   <short_name>Lisbon</short_name>
   <type>locality</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Lisbon</long_name>
   <short_name>Lisbon</short_name>
   <type>administrative_area_level_1</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Portugal</long_name>
   <short_name>PT</short_name>
   <type>country</type>
   <type>political</type>
  </address_component>
  <geometry>
   <location>
    <lat>38.7222524</lat>
    <lng>-9.1393366</lng>
   </location>
   <location_type>APPROXIMATE</location_type>
   <viewport>
    <southwest>
     <lat>38.6913994</lat>
     <lng>-9.2298356</lng>
    </southwest>
    <northeast>
     <lat>38.7958538</lat>
     <lng>-9.0905718</lng>
    </northeast>
   </viewport>
   <bounds>
    <southwest>
     <lat>38.6913994</lat>
     <lng>-9.2298356</lng>
    </southwest>
    <northeast>
     <lat>38.7958538</lat>
     <lng>-9.0905718</lng>
    </northeast>
   </bounds>
  </geometry>
  <place_id>ChIJO_PkYRozGQ0R0DaQ5L3rAAQ</place_id>
 </result>
 <result>
  <type>postal_code</type>
  <formatted_address>1700-111 Lisbon, Portugal</formatted_address>
  <address_component>
   <long_name>1700-111</long_name>
   <short_name>1700-111</short_name>
   <type>postal_code</type>
  </address_component>
  <address_component>
   <long_name>Lisbon</long_name>
   <short_name>Lisbon</short_name>
   <type>locality</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Olivais</long_name>
   <short_name>Olivais</short_name>
   <type>administrative_area_level_3</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Lisbon</long_name>
   <short_name>Lisbon</short_name>
   <type>administrative_area_level_2</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Lisbon</long_name>
   <short_name>Lisbon</short_name>
   <type>administrative_area_level_1</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Portugal</long_name>
   <short_name>PT</short_name>
   <type>country</type>
   <type>political</type>
  </address_component>
  <geometry>
   <location>
    <lat>38.7661892</lat>
    <lng>-9.1291486</lng>
   </location>
   <location_type>APPROXIMATE</location_type>
   <viewport>
    <southwest>
     <lat>38.7544060</lat>
     <lng>-9.1483947</lng>
    </southwest>
    <northeast>
     <lat>38.7870843</lat>
     <lng>-9.1239064</lng>
    </northeast>
   </viewport>
   <bounds>
    <southwest>
     <lat>38.7544060</lat>
     <lng>-9.1483947</lng>
    </southwest>
    <northeast>
     <lat>38.7870843</lat>
     <lng>-9.1239064</lng>
    </northeast>
   </bounds>
  </geometry>
  <place_id>ChIJS-qk_0UyGQ0RN3v7SZnU9D8</place_id>
 </result>
 <result>
  <type>postal_code_prefix</type>
  <type>postal_code</type>
  <formatted_address>1700, Portugal</formatted_address>
  <address_component>
   <long_name>1700</long_name>
   <short_name>1700</short_name>
   <type>postal_code_prefix</type>
   <type>postal_code</type>
  </address_component>
  <address_component>
   <long_name>Lisbon</long_name>
   <short_name>Lisbon</short_name>
   <type>administrative_area_level_1</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Portugal</long_name>
   <short_name>PT</short_name>
   <type>country</type>
   <type>political</type>
  </address_component>
  <geometry>
   <location>
    <lat>38.7600325</lat>
    <lng>-9.1400807</lng>
   </location>
   <location_type>APPROXIMATE</location_type>
   <viewport>
    <southwest>
     <lat>38.7448641</lat>
     <lng>-9.1567550</lng>
    </southwest>
    <northeast>
     <lat>38.7870843</lat>
     <lng>-9.1239064</lng>
    </northeast>
   </viewport>
   <bounds>
    <southwest>
     <lat>38.7448641</lat>
     <lng>-9.1567550</lng>
    </southwest>
    <northeast>
     <lat>38.7870843</lat>
     <lng>-9.1239064</lng>
    </northeast>
   </bounds>
  </geometry>
  <place_id>ChIJdVtq_1kyGQ0RYKU7DsHrABw</place_id>
 </result>
 <result>
  <type>administrative_area_level_3</type>
  <type>political</type>
  <formatted_address>Olivais, Portugal</formatted_address>
  <address_component>
   <long_name>Olivais</long_name>
   <short_name>Olivais</short_name>
   <type>administrative_area_level_3</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Lisbon</long_name>
   <short_name>Lisbon</short_name>
   <type>administrative_area_level_2</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Lisbon</long_name>
   <short_name>Lisbon</short_name>
   <type>administrative_area_level_1</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Portugal</long_name>
   <short_name>PT</short_name>
   <type>country</type>
   <type>political</type>
  </address_component>
  <geometry>
   <location>
    <lat>38.7721510</lat>
    <lng>-9.1179465</lng>
   </location>
   <location_type>APPROXIMATE</location_type>
   <viewport>
    <southwest>
     <lat>38.7502229</lat>
     <lng>-9.1483924</lng>
    </southwest>
    <northeast>
     <lat>38.7870963</lat>
     <lng>-9.0905718</lng>
    </northeast>
   </viewport>
   <bounds>
    <southwest>
     <lat>38.7502229</lat>
     <lng>-9.1483924</lng>
    </southwest>
    <northeast>
     <lat>38.7870963</lat>
     <lng>-9.0905718</lng>
    </northeast>
   </bounds>
  </geometry>
  <place_id>ChIJccbEUz4yGQ0RsEKQ5L3rAAU</place_id>
 </result>
 <result>
  <type>administrative_area_level_2</type>
  <type>political</type>
  <formatted_address>Lisbon, Portugal</formatted_address>
  <address_component>
   <long_name>Lisbon</long_name>
   <short_name>Lisbon</short_name>
   <type>administrative_area_level_2</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Lisbon</long_name>
   <short_name>Lisbon</short_name>
   <type>administrative_area_level_1</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Portugal</long_name>
   <short_name>PT</short_name>
   <type>country</type>
   <type>political</type>
  </address_component>
  <geometry>
   <location>
    <lat>38.7222986</lat>
    <lng>-9.1393188</lng>
   </location>
   <location_type>APPROXIMATE</location_type>
   <viewport>
    <southwest>
     <lat>38.6913994</lat>
     <lng>-9.2298356</lng>
    </southwest>
    <northeast>
     <lat>38.7958538</lat>
     <lng>-9.0905718</lng>
    </northeast>
   </viewport>
   <bounds>
    <southwest>
     <lat>38.6913994</lat>
     <lng>-9.2298356</lng>
    </southwest>
    <northeast>
     <lat>38.7958538</lat>
     <lng>-9.0905718</lng>
    </northeast>
   </bounds>
  </geometry>
  <place_id>ChIJMabWPRAzGQ0RRFqNEqmj6AI</place_id>
 </result>
 <result>
  <type>administrative_area_level_1</type>
  <type>political</type>
  <formatted_address>Lisbon, Portugal</formatted_address>
  <address_component>
   <long_name>Lisbon</long_name>
   <short_name>Lisbon</short_name>
   <type>administrative_area_level_1</type>
   <type>political</type>
  </address_component>
  <address_component>
   <long_name>Portugal</long_name>
   <short_name>PT</short_name>
   <type>country</type>
   <type>political</type>
  </address_component>
  <geometry>
   <location>
    <lat>38.7223263</lat>
    <lng>-9.1392714</lng>
   </location>
   <location_type>APPROXIMATE</location_type>
   <viewport>
    <southwest>
     <lat>38.6731604</lat>
     <lng>-9.5005266</lng>
    </southwest>
    <northeast>
     <lat>39.3177286</lat>
     <lng>-8.7819208</lng>
    </northeast>
   </viewport>
   <bounds>
    <southwest>
     <lat>38.6731604</lat>
     <lng>-9.5005266</lng>
    </southwest>
    <northeast>
     <lat>39.3177286</lat>
     <lng>-8.7819208</lng>
    </northeast>
   </bounds>
  </geometry>
  <place_id>ChIJWxIr4ajVGA0RwCyQ5L3rAAM</place_id>
 </result>
 <result>
  <type>country</type>
  <type>political</type>
  <formatted_address>Portugal</formatted_address>
  <address_component>
   <long_name>Portugal</long_name>
   <short_name>PT</short_name>
   <type>country</type>
   <type>political</type>
  </address_component>
  <geometry>
   <location>
    <lat>39.3998720</lat>
    <lng>-8.2244540</lng>
   </location>
   <location_type>APPROXIMATE</location_type>
   <viewport>
    <southwest>
     <lat>36.9601772</lat>
     <lng>-9.5171107</lng>
    </southwest>
    <northeast>
     <lat>42.1542048</lat>
     <lng>-6.1902091</lng>
    </northeast>
   </viewport>
   <bounds>
    <southwest>
     <lat>32.4037400</lat>
     <lng>-31.2752439</lng>
    </southwest>
    <northeast>
     <lat>42.1542048</lat>
     <lng>-6.1902091</lng>
    </northeast>
   </bounds>
  </geometry>
  <place_id>ChIJ1SZCvy0kMgsRQfBOHAlLuCo</place_id>
 </result>
</GeocodeResponse>

我使用 google 提供的相同反向地理服务实现了类似的东西,但 JSON 版本。根据我的经验,您不能假设您需要的任何数据,例如城市,会在那里。您还可能需要检查零结果。看看下面我是如何实现它的:

public async Task<LocationAddressModel> GetLocationAddressAsync (LocationAddressRequest locationAddressRequest)
    {
        Task<IRestResponse> task = GetAddressForLocation (locationAddressRequest);
        IRestResponse response = await task;
        var locationAddress = new LocationAddressModel ();
        if (response != null) {
            RootObject locationAddresses = JsonConvert.DeserializeObject<RootObject> (response.Content);
            if (locationAddresses.status.Equals (Constants.ZERO_RESULTS)) {
                // Zero results for that location, setting location to Unknown.
                locationAddress.FormattedAddress = "UnknownLocation".Local();
                locationAddress.City = "CityNotFound".Local ();
                locationAddress.County = "CountyNotFound".Local ();
                locationAddress.FirstLineOfAddress = "AddressNotFound".Local ();
                locationAddress.Postcode = "PostcodeNotFound".Local ();
            } else {
                try {
                    Result routeAddress = locationAddresses.results.FirstOrDefault (x => x.types.Contains (Constants.ROUTE));
                    if (routeAddress != null) 
                    {
                        locationAddress.FormattedAddress = routeAddress.formatted_address;

                        var postcode = routeAddress.address_components.FirstOrDefault(x => x.types.Contains (Constants.POSTCODE));
                        locationAddress.Postcode = postcode != null ? postcode.long_name : "PostcodeNotFound".Local ();

                        var firstLineOfAddress = routeAddress.address_components.FirstOrDefault(x => x.types.Contains (Constants.ROUTE));
                        locationAddress.FirstLineOfAddress = firstLineOfAddress != null ? firstLineOfAddress.long_name : "AddressNotFound".Local ();

                        var city = routeAddress.address_components.FirstOrDefault(x => x.types.Contains (Constants.CITY));
                        locationAddress.City = city != null ? city.long_name : "CityNotFound".Local ();

                    } 
                    else 
                    {
                        // If the location doesnt have a route address just return the first result formatted address
                        locationAddress.FormattedAddress = locationAddresses.results.FirstOrDefault ().formatted_address;
                    }

                    // Remove any numbers at the start, to save users from knowing how inaccurate GPS can be.
                    locationAddress.FormattedAddress = Regex.Replace (locationAddress.FormattedAddress, "^\d+\s", string.Empty);
                } 
                catch (Exception e)
                {
                    Debug.WriteLine ("Exception in reverse geolocation data");
                    // If we get some crazy data also set it to unknown
                    locationAddress.FormattedAddress = "UnknownLocation".Local();
                }
            }
        }
        return locationAddress;
    }

private async Task<IRestResponse> GetAddressForLocation (LocationAddressRequest locationAddressRequest) {

            IRestRequest restRequest = _restSharpGoogleMapsSingletonBase.Factory.Create(Constants.GET_LOCATION_ADDRESS, Method.GET);

            restRequest.AddUrlSegment ("lat", locationAddressRequest.Lat);
            restRequest.AddUrlSegment ("lng", locationAddressRequest.Lng);

            try
            {
                var result = await _helper.ExecuteTaskAsync(restRequest);

                if (result.StatusCode == (int)HttpStatusCode.OK)
                {
                    Debug.WriteLine("Rest Request Succeeded in Google Maps GeoCode API");
                    return result;
                }
                else
                {
                    Debug.WriteLine("Rest Request Failed in Google Maps GeoCode API: Wrong status code received");
                    return null;
                }
            }
            catch(WebException webException)
            {
                // Windows Store application profile only supports a limited set of WebExceptionStatus. 
                // So the PCL can only support that set, Check for the Timeout here.
                if(webException.Status == (WebExceptionStatus)14)
                {
                    Debug.WriteLine("Timed out in Google Maps GeoCode API");
                }
                return null;
            }
            catch (Exception exception)
            {
                return null;
            }

        }

我正在使用的常量:

namespace GoogleMaps
{
    public static class Constants
    {
        public static string GOOGLEMAPSURL = "http://maps.googleapis.com/";
        public static string GET_LOCATION_ADDRESS = "/maps/api/geocode/json?latlng={lat},{lng}";

        public static string ROUTE = "route";
        public static string FORMATTED_ADDRESS = "formatted_address";
        public static string POSTCODE = "postal_code";
        public static string CITY = "locality";

        public static string ZERO_RESULTS = "ZERO_RESULTS";
    }
}

希望对您有所帮助。

问题发生在

string type = typeElement.FirstOrDefault ().Value;

所以我必须测试是否 typeElement.FirstOrDefault () != null

如下:

    private async Task<string> ReturnCity(string lat, string lon)
    {
        string city = "None";
        string baseUri = string.Format ("http://maps.googleapis.com/maps/api/geocode/xml?latlng={0},{1}&sensor=false", lat, lon);
        HttpClient client = new HttpClient ();
        string response = await client.GetStringAsync (baseUri);
        XElement responseElement = XElement.Parse (response);
        IEnumerable<XElement> statusElement = from st in responseElement.Elements ("status")
                                               select st;
        if (statusElement.FirstOrDefault () != null) {
            string status = statusElement.FirstOrDefault ().Value;
            if (status.ToLower () == "ok") {
                IEnumerable<XElement> resultElement = from rs in responseElement.Elements ("result")
                                                      select rs;
                if (resultElement.FirstOrDefault () != null) {
                    IEnumerable<XElement> addressElement = from ad in resultElement.FirstOrDefault ().Elements ("address_component")
                                                           select ad;
                    foreach (XElement element in addressElement) {
                        IEnumerable<XElement> typeElement = from te in element.Elements ("type")
                                                            select te;
                        if (typeElement.FirstOrDefault () != null) {
                            string type = typeElement.FirstOrDefault ().Value;
                            if (type == "locality") {
                                IEnumerable<XElement> cityElement = from ln in element.Elements ("long_name")
                                                                   select ln;
                                city = cityElement.FirstOrDefault ().Value;
                                return city;
                            }
                        }
                    }
                }
            }
        }

        return city;
    }