【问题标题】:Service not available in geoCodergeoCoder 中不提供服务
【发布时间】:2012-02-14 06:57:38
【问题描述】:

我可以获取经度和纬度,但获取地址时出错。

public boolean onTouchEvent(MotionEvent event, MapView mapView)

{

  if(event.getAction()==0)

   {

GeoPoint p = mapView.getProjection().fromPixels(

  (int) event.getX(),

  (int) event.getY());


Geocoder geoCoder=new Geocoder(getBaseContext(),Locale.getDefault());

 try

   {

   List<Address> address = geoCoder.getFromLocation( p.getLatitudeE6() / 1E6,
                            p.getLongitudeE6() / 1E6, 1);

    String add="";

       if(address.size()>0)

          {

              for (int i=0; i<address.get(0).getMaxAddressLineIndex();i++)

        add += address.get(0).getAddressLine(i) + "\n";

          }

    Toast.makeText(getBaseContext(), add, Toast.LENGTH_SHORT).show();

            } catch (IOException e) 

            {   

                e.printStackTrace();

            }

            return true;    

        }

        return false;

}

我的 Logcat -->

02-14 12:27:35.717: WARN/System.err(452): java.io.IOException: Service not Available
02-14 12:27:35.727: WARN/System.err(452):     at android.location.Geocoder.getFromLocation(Geocoder.java:117)
02-14 12:27:35.727: WARN/System.err(452):     at com.parkhya.SecondGps.MainActivity$MapOverlay.onTouchEvent(MainActivity.java:47)
02-14 12:27:35.745: WARN/System.err(452):     at com.google.android.maps.OverlayBundle.onTouchEvent(OverlayBundle.java:63)
02-14 12:27:35.745: WARN/System.err(452):     at com.google.android.maps.MapView.onTouchEvent(MapView.java:643)
02-14 12:27:35.757: WARN/System.err(452):     at android.view.View.dispatchTouchEvent(View.java:3766)
02-14 12:27:35.757: WARN/System.err(452):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:897)
02-14 12:27:35.757: WARN/System.err(452):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:863)
02-14 12:27:35.767: WARN/System.err(452):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:863)
02-14 12:27:35.767: WARN/System.err(452):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:863)
02-14 12:27:35.777: WARN/System.err(452):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:863)
02-14 12:27:35.777: WARN/System.err(452):     at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1671)
02-14 12:27:35.777: WARN/System.err(452):     at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1107)
02-14 12:27:35.777: WARN/System.err(452):     at android.app.Activity.dispatchTouchEvent(Activity.java:2086)
02-14 12:27:35.786: WARN/System.err(452):     at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1655)
02-14 12:27:35.786: WARN/System.err(452):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1785)
02-14 12:27:35.796: WARN/System.err(452):     at android.os.Handler.dispatchMessage(Handler.java:99)
02-14 12:27:35.796: WARN/System.err(452):     at android.os.Looper.loop(Looper.java:123)
02-14 12:27:35.796: WARN/System.err(452):     at android.app.ActivityThread.main(ActivityThread.java:4627)
02-14 12:27:35.806: WARN/System.err(452):     at java.lang.reflect.Method.invokeNative(Native Method)
02-14 12:27:35.816: WARN/System.err(452):     at java.lang.reflect.Method.invoke(Method.java:521)
02-14 12:27:35.816: WARN/System.err(452):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
02-14 12:27:35.825: WARN/System.err(452):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
02-14 12:27:35.837: WARN/System.err(452):     at dalvik.system.NativeStart.main(Native Method)

【问题讨论】:

    标签: android gps


    【解决方案1】:

    即使 Geocoder 失败,我也是这样获取地址的……但首先让我解释一下我自己使用 Geocoder 的经验:

    出于某种未知原因,Geocoder 工作正常,然后突然坏了!

    我观察到,过了一段时间(可能是几天),Geocoder 开始抛出“服务不可用”异常。

    EDIT-> 正如Christian 所述,即使isPresent() 返回true,也会引发异常。EDIT END

    真的很奇怪,因为它之前工作正常并且没有发生任何配置更改:

    • 同一设备
    • 安卓版本相同
    • 同一个应用
    • 相同的清单
    • WIFI 启动并运行,在设置中启用设备定位功能

    当然,有些东西发生了变化,但是,我们暂时不知道具体是什么。 有一个关于此的错误:Issue 38009: 4.1.1 Geocoder throwing exception: IOException: Service not Available

    此线程上的最后一篇文章(ATTOW)“它可能在 android 4.0.x + 目标 API x 中定期重现”

    作为一种解决方法,您可以使用 Google 地图

    这是我的 GeocoderHelper 类,它提供了一个“谷歌地图”B 计划,以防地理编码器开始失败。 就我而言,我只对 CityName 感兴趣,但您基本上可以在 google map JSON 输出中获取任何可用数据

    用法:

    new GeocoderHelper().fetchCityName(context, location); 然后在示例代码的 onPostExecute() 中做一些事情(发送广播、调用侦听器方法、设置 textView 文本等)

    GeocoderHelper 类:

    package com.<your_package>.location;
    
    import java.util.List;
    import java.util.Locale;
    
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.impl.client.BasicResponseHandler;
    import org.json.JSONArray;
    import org.json.JSONObject;
    
    import android.content.Context;
    import android.location.Address;
    import android.location.Geocoder;
    import android.location.Location;
    import android.net.http.AndroidHttpClient;
    import android.os.AsyncTask;
    import android.util.Log;
    
    public class GeocoderHelper
    {
        private static final AndroidHttpClient ANDROID_HTTP_CLIENT = AndroidHttpClient.newInstance(GeocoderHelper.class.getName());
    
        private boolean running = false;
    
        public void fetchCityName(final Context contex, final Location location)
        {
            if (running)
                return;
    
            new AsyncTask<Void, Void, String>()
            {
                protected void onPreExecute()
                {
                    running = true;
                };
    
                @Override
                protected String doInBackground(Void... params)
                {
                    String cityName = null;
    
                    if (Geocoder.isPresent())
                    {
                        try
                        {
                            Geocoder geocoder = new Geocoder(contex, Locale.getDefault());
                            List<Address> addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
                            if (addresses.size() > 0)
                            {
                                cityName = addresses.get(0).getLocality();
                            }
                        }
                        catch (Exception ignored)
                        {
                            // after a while, Geocoder start to trhow "Service not availalbe" exception. really weird since it was working before (same device, same Android version etc..
                        }
                    }
    
                    if (cityName != null) // i.e., Geocoder succeed
                    {
                        return cityName;
                    }
                    else // i.e., Geocoder failed
                    {
                        return fetchCityNameUsingGoogleMap();
                    }
                }
    
                // Geocoder failed :-(
                // Our B Plan : Google Map
                private String fetchCityNameUsingGoogleMap()
                {
                    String googleMapUrl = "http://maps.googleapis.com/maps/api/geocode/json?latlng=" + location.getLatitude() + ","
                            + location.getLongitude() + "&sensor=false&language=fr";
    
                    try
                    {
                        JSONObject googleMapResponse = new JSONObject(ANDROID_HTTP_CLIENT.execute(new HttpGet(googleMapUrl),
                                new BasicResponseHandler()));
    
                        // many nested loops.. not great -> use expression instead
                        // loop among all results
                        JSONArray results = (JSONArray) googleMapResponse.get("results");
                        for (int i = 0; i < results.length(); i++)
                        {
                            // loop among all addresses within this result
                            JSONObject result = results.getJSONObject(i);
                            if (result.has("address_components"))
                            {
                                JSONArray addressComponents = result.getJSONArray("address_components");
                                // loop among all address component to find a 'locality' or 'sublocality'
                                for (int j = 0; j < addressComponents.length(); j++)
                                {
                                    JSONObject addressComponent = addressComponents.getJSONObject(j);
                                    if (result.has("types"))
                                    {
                                        JSONArray types = addressComponent.getJSONArray("types");
    
                                        // search for locality and sublocality
                                        String cityName = null;
    
                                        for (int k = 0; k < types.length(); k++)
                                        {
                                            if ("locality".equals(types.getString(k)) && cityName == null)
                                            {
                                                if (addressComponent.has("long_name"))
                                                {
                                                    cityName = addressComponent.getString("long_name");
                                                }
                                                else if (addressComponent.has("short_name"))
                                                {
                                                    cityName = addressComponent.getString("short_name");
                                                }
                                            }
                                            if ("sublocality".equals(types.getString(k)))
                                            {
                                                if (addressComponent.has("long_name"))
                                                {
                                                    cityName = addressComponent.getString("long_name");
                                                }
                                                else if (addressComponent.has("short_name"))
                                                {
                                                    cityName = addressComponent.getString("short_name");
                                                }
                                            }
                                        }
                                        if (cityName != null)
                                        {
                                            return cityName;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception ignored)
                    {
                        ignored.printStackTrace();
                    }
                    return null;
                }
    
                protected void onPostExecute(String cityName)
                {
                    running = false;
                    if (cityName != null)
                    {
                        // Do something with cityName
                        Log.i("GeocoderHelper", cityName);
                    }
                };
            }.execute();
        }
    }
    

    希望这会有所帮助。

    【讨论】:

    • 嗨 Pascal,感谢分享,我首先认为解决方法不好,直到我发现即使 isPresent() 返回 true 服务有时直到重新启动后才可用。由于这对于任何应用程序来说都是出乎意料的行为,因此我建议您采用更好的方式。
    • 有什么方法可以方便地将JSONObject googleMapResponse解析成android.location.Address对象列表?
    • 抱歉,我没有对此进行调查。
    • long_name 总是国家名吗?
    • @DennyWeinberg 我不知道,抱歉。
    【解决方案2】:

    GeoCoder 服务可能/可能不会实现,因为它不是核心 android 框架的一部分。查看 GeoCoder 的文档here

    您需要使用 google API 并从 json 响应中解析地址,以便它在所有设备上工作。

    处理地理编码和反向地理编码的类。地理编码是将街道地址或位置的其他描述转换为(纬度、经度)坐标的过程。反向地理编码是将(纬度、经度)坐标转换为(部分)地址的过程。反向地理编码位置描述中的详细信息量可能会有所不同,例如,一个可能包含最近建筑物的完整街道地址,而另一个可能仅包含城市名称和邮政编码。 Geocoder 类需要一个不包含在核心 android 框架中的后端服务。如果平台中没有后端服务,Geocoder 查询方法将返回一个空列表。使用 isPresent() 方法确定是否存在 Geocoder 实现。

    【讨论】:

    • 即使 isPresent() 返回 true 也不能保证您的地理编码器服务仍在运行。
    【解决方案3】:

    问题是 NetworkLocationService 可能不再运行。

    只能通过重启解决。 (NetworkLocationService 在启动时加载)

    【讨论】:

    • 悲伤,但确实如此。但是在使用应用程序时发生这种情况怎么办?向用户显示他必须重新启动您的设备的消息?
    猜你喜欢
    • 2020-12-21
    • 2011-10-29
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    • 2012-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多