按位置获取城市名称和国家/地区名称

时间:2014-11-29 11:03:53

标签: android android-location google-geocoder

我正在尝试通过android中的给定位置获取cityname和国家/地区名称,但我无法做到这一点。我需要在所有情况下获得它们,没有gps,互联网连接,或者所有这些都打开了。 我试过了GeoCoder,但我收到了这个错误:

11-29 11:54:01.718: W/System.err(32200):    at com.myapp.Main$4.gotLocation(Main.java:282)
11-29 11:54:01.718: W/System.err(32200):    at com.myapp.services.MyLocation$GetLastLocation.run(MyLocation.java:124)

geoCoder位于我的MainActivity中的gotLocation内部

这是我的代码:

Log.v("--", "got location ="+location.getLatitude()+" | "+location.getLongitude());
try {
    Geocoder gcd = new Geocoder(Main.this, Locale.getDefault());
    List<Address> addresses;

    //im getting an error in this line and checked location values are OK
    addresses = gcd.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
    Log.v("--", addresses.size()+" got location address size");
    if (addresses.size() > 0) {
        city = addresses.get(0).getLocality();
        country = addresses.get(0).getCountryName();
        prefs.edit().putString(Constants.COUNTRY, country).commit();
        prefs.edit().putString(Constants.CITY, city).commit();
    } else {
        city = a.getString(R.string.app_name);
        country = "France";
    }

    Log.v("--", "got location"+city+" | "+country);
}catch(Exception e){
    Log.v("--", "got location failed");
    e.printStackTrace();
}

和MyLocation类代码:

public class MyLocation {
    Timer timer1;
    LocationManager lm;
    LocationResult locationResult;
    boolean gps_enabled = false;
    boolean network_enabled = false;
    private Context context;

    public boolean getLocation(Context context, LocationResult result) {
        // I use LocationResult callback class to pass location value from
        // MyLocation to user code.
        locationResult = result;
        this.context = context;
        if (lm == null)
            lm = (LocationManager) context
                    .getSystemService(Context.LOCATION_SERVICE);

        // exceptions will be thrown if provider is not permitted.
        try {
            gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
        } catch (Exception ex) {
        }
        try {
            network_enabled = lm
                    .isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        } catch (Exception ex) {
        }

        // don't start listeners if no provider is enabled
        if (!gps_enabled && !network_enabled)
            return false;

        if (gps_enabled)
            lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
                    locationListenerGps);
        if (network_enabled)
            lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0,
                    locationListenerNetwork);
        timer1 = new Timer();
        timer1.schedule(new GetLastLocation(), 20000);
        return true;
    }

    LocationListener locationListenerGps = new LocationListener() {
        public void onLocationChanged(Location location) {
            timer1.cancel();
            locationResult.gotLocation(location);
            lm.removeUpdates(this);
            lm.removeUpdates(locationListenerNetwork);
        }

        public void onProviderDisabled(String provider) {
        }

        public void onProviderEnabled(String provider) {
        }

        public void onStatusChanged(String provider, int status, Bundle extras) {
        }
    };

    LocationListener locationListenerNetwork = new LocationListener() {
        public void onLocationChanged(Location location) {
            timer1.cancel();
            locationResult.gotLocation(location);
            lm.removeUpdates(this);
            lm.removeUpdates(locationListenerGps);
        }

        public void onProviderDisabled(String provider) {
        }

        public void onProviderEnabled(String provider) {
        }

        public void onStatusChanged(String provider, int status, Bundle extras) {
        }
    };

    class GetLastLocation extends TimerTask {
        private Handler mHandler = new Handler(Looper.getMainLooper());
        Location net_loc,gps_loc;
        @Override
        public void run() {
            mHandler.post(new Runnable() {
                public void run() {
            lm.removeUpdates(locationListenerGps);
            lm.removeUpdates(locationListenerNetwork);

            net_loc = null; gps_loc = null;
            if (gps_enabled)
                gps_loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
            if (network_enabled)
                net_loc = lm
                        .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

            // if there are both values use the latest one
            if (gps_loc != null && net_loc != null) {
                if (gps_loc.getTime() > net_loc.getTime())
                    locationResult.gotLocation(gps_loc);
                else
                    locationResult.gotLocation(net_loc);
                return;
            }

            if (gps_loc != null) {
                locationResult.gotLocation(gps_loc);
                timer1.notifyAll();

                return;
            }
            if (net_loc != null) {
                locationResult.gotLocation(net_loc);
                return;

            }

                    locationResult.gotLocation(null);
                }
            });
        }

    }

    public void cancelTimer() {
        timer1.cancel();
        lm.removeUpdates(locationListenerGps);
        lm.removeUpdates(locationListenerNetwork);
    }

    public static abstract class LocationResult {

        public abstract void gotLocation(Location location);

    }
}

那么有人可以帮我解决这个问题吗?

1 个答案:

答案 0 :(得分:0)

您可以使用以下代码

public class GeocoderModel {

    private String streetNumber;
    private String rout;
    private String subLocality;
    private String political;
    private String country;

   // getter and setter
  }

自定义geoCoder类:

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.location.Address;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.Locale;

/**
 * A class for handling geocoding and reverse geocoding. Geocoding is the
 * process of transforming a street address or other description of a location
 * into a (latitude, longitude) coordinate. Reverse geocoding is the process of
 * transforming a (latitude, longitude) coordinate into a (partial) address. The
 * amount of detail in a reverse geocoded location description may vary, for
 * example one might contain the full street address of the closest building,
 * while another might contain only a city name and postal code.
 * <p/>
 * This is a replacement of built-in Geocoder which is not always available.
 * This implementation parses just a formatted address and is guaranteed to
 * work.
 */
public final class Geocoder {

    private static final String PREFERENCES_GEOCODER = Geocoder.class.getName()
            + ".GEOCODER";
    private static final String KEY_ALLOW = Geocoder.class.getName()
            + ".KEY_ALLOW";

    /*
     * Status codes which we handle
     */

    /**
     * Indicates that no errors occurred; the address was successfully parsed
     * and at least one geocode was returned.
     */
    private static final String STATUS_OK = "OK";

    /**
     * Indicates that you are over your quota.
     */
    private static final String STATUS_OVER_QUERY_LIMIT = "OVER_QUERY_LIMIT";

    private final Context context;

    /**
     * Constructs a Geocoder whose responses will be localized for the default
     * system Locale.
     *
     * @param context the Context of the calling Activity
     */
    public Geocoder(Context context) {
        this.context = context;
    }

    /**
     * Returns an array of Addresses that are known to describe the area
     * immediately surrounding the given latitude and longitude. The returned
     * addresses will be localized for the locale provided to this class's
     * constructor.
     * <p/>
     * <p/>
     * The returned values may be obtained by means of a network lookup. The
     * results are a best guess and are not guaranteed to be meaningful or
     * correct. It may be useful to call this method from a thread separate from
     * your primary UI thread.
     *
     * @param latitude   the latitude a point for the search
     * @param longitude  the longitude a point for the search
     * @param maxResults max number of addresses to return. Smaller numbers (1 to 5)
     *                   are recommended
     * @return a list of Address objects. Returns null or empty list if no
     * matches were found or there is no backend service available.
     * @throws IllegalArgumentException if latitude is less than -90 or greater than 90
     * @throws IllegalArgumentException if longitude is less than -180 or greater than 180
     * @throws java.io.IOException      if the network is unavailable or any other I/O problem occurs
     */
    public GeocoderModel getFromLocation(double latitude, double longitude,
                                         int maxResults) throws IOException, LimitExceededException {
        if (latitude < -90.0 || latitude > 90.0) {
            throw new IllegalArgumentException("latitude == " + latitude);
        }
        if (longitude < -180.0 || longitude > 180.0) {
            throw new IllegalArgumentException("longitude == " + longitude);
        }

        if (isLimitExceeded(context)) {
            throw new LimitExceededException();
        }

        final GeocoderModel results = new GeocoderModel();

        final StringBuilder url = new StringBuilder(
                "http://maps.googleapis.com/maps/api/geocode/json?sensor=true&latlng=");
        url.append(latitude);
        url.append(',');
        url.append(longitude);
        url.append("&language=");
        url.append(Locale.ENGLISH);

        final byte[] data = WebserviceClient.download(url.toString());
        if (data != null) {
            this.parseJson(results, maxResults, data);
        }
        return results;
    }

    /**
     * Returns an array of Addresses that are known to describe the named
     * location, which may be a place name such as "Dalvik,
     * Iceland", an address such as "1600 Amphitheatre Parkway, Mountain View,
     * CA", an airport code such as "SFO", etc.. The returned addresses will be
     * localized for the locale provided to this class's constructor.
     * <p/>
     * <p/>
     * The query will block and returned values will be obtained by means of a
     * network lookup. The results are a best guess and are not guaranteed to be
     * meaningful or correct. It may be useful to call this method from a thread
     * separate from your primary UI thread.
     *
     * @param locationName a user-supplied description of a location
     * @param maxResults   max number of results to return. Smaller numbers (1 to 5) are
     *                     recommended
     * @return a list of Address objects. Returns null or empty list if no
     * matches were found or there is no backend service available.
     * @throws IllegalArgumentException if locationName is null
     * @throws java.io.IOException      if the network is unavailable or any other I/O problem occurs
     */
    public GeocoderModel getFromLocationName(String locationName, int
            maxResults)
            throws IOException, LimitExceededException {
        if (locationName == null) {
            throw new IllegalArgumentException("locationName == null");
        }

        if (isLimitExceeded(context)) {
            throw new LimitExceededException();
        }

        final GeocoderModel results = new GeocoderModel();

        final StringBuilder request = new StringBuilder(
                "http://maps.googleapis.com/maps/api/geocode/json?sensor=false");
        request.append("&language=").append(Locale.getDefault().getLanguage());
        request.append("&address=").append(
                URLEncoder.encode(locationName, "UTF-8"));

        byte[] data = WebserviceClient.download(request.toString());
        if (data != null) {
            try {
                this.parseJson(results, maxResults, data);
            } catch (LimitExceededException e) {
                // LimitExceededException could be thrown if too many calls per
                // second
                // If after two seconds, it is thrown again - then it means
                // there are too much calls per 24 hours
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e1) {
                    return results;
                }
                data = WebserviceClient.download(request.toString());
                if (data != null) {
                    try {
                        this.parseJson(results, maxResults, data);
                    } catch (LimitExceededException lee) {
                        // available in 24 hours
                        setAllowedDate(context,
                                System.currentTimeMillis() + 86400000L);
                        throw lee;
                    }
                }
            }
        }
        return results;
    }

    private void parseJson(GeocoderModel geoCoderModel, int maxResults,
                           byte[] data) throws LimitExceededException {
        try {
            final String json = new String(data, "UTF-8");
            final JSONObject o = new JSONObject(json);
            final String status = o.getString("status");
            if (status.equals(STATUS_OK)) {

                final JSONArray a = o.getJSONArray("results");

                // for (int i = 0; i < maxResults && i < a.length(); i++) {

                final Address current = new Address(Locale.getDefault());
                final JSONObject item = a.getJSONObject(0);
                JSONArray addressComponnet = item
                        .getJSONArray("address_components");

                for (int i = 0; i < addressComponnet.length(); i++) {

                    JSONObject temp = addressComponnet.getJSONObject(i);

                    Log.d("temp is", temp.toString());

                    JSONArray type = temp.getJSONArray("types");

                    if (type.toString().contains("street_number")) {
                        geoCoderModel.setStreetNumber(temp
                                .getString("long_name"));
                    } else if (type.toString().contains("rout")) {
                        geoCoderModel.setRout(temp.getString("long_name"));
                    } else if (type.toString().contains("country")) {
                        geoCoderModel.setCountry(temp.getString("long_name"));
                    } else if (type.toString().contains("political")) {
                        if ((geoCoderModel.getPolitical().length() - geoCoderModel
                                .getPolitical().replace("|", "").length()) < 3
                                || type.toString().contains(
                                "administrative_area_level_1"))
                            geoCoderModel.setPolitical(temp
                                    .getString("long_name"));
                    } else if (type.toString().contains("sublocality")) {
                        geoCoderModel.setRout(geoCoderModel.getRout() + " "
                                + temp.getString("long_name"));
                    }

                }
            } else if (status.equals(STATUS_OVER_QUERY_LIMIT)) {

                throw new LimitExceededException();

            }
        } catch (LimitExceededException e) {
            throw e;
        } catch (Throwable e) {
            e.printStackTrace();
        }

    }

    /**
     * Returns true if limit is exceeded and next query is not allowed
     *
     * @param context Current context
     * @return true if limit is exceeded and next query is not allowed; false
     * otherwise
     */
    private static boolean isLimitExceeded(Context context) {
        return System.currentTimeMillis() <= getAllowedDate(context);
    }

    /**
     * Sets date after which next geocoding query is allowed
     *
     * @param context Current context
     * @param date    the date after which next geocoding query is allowed
     */
    private static void setAllowedDate(Context context, long date) {
        final SharedPreferences p = context.getSharedPreferences(
                PREFERENCES_GEOCODER, Context.MODE_PRIVATE);
        final Editor e = p.edit();
        e.putLong(KEY_ALLOW, date);
        e.commit();
    }

    /**
     * Returns date after which the next geocoding query is allowed
     *
     * @param context Current context
     * @return date after which the next geocoding query is allowed
     */
    private static long getAllowedDate(Context context) {
        final SharedPreferences p = context.getSharedPreferences(
                PREFERENCES_GEOCODER, Context.MODE_PRIVATE);
        return p.getLong(KEY_ALLOW, 0);
    }

    /**
     * Is thrown when the query was over limit before 24 hours
     */
    public static final class LimitExceededException extends Exception {
        private static final long serialVersionUID = -1243645207607944474L;
    }

}

WebServiceClient此类:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class WebserviceClient {

    public static byte[] download(String url) {
        InputStream is = null;
        ByteArrayOutputStream os = null;

        try {

            final URL u = new URL(url);
            final URLConnection connection = u.openConnection();
            connection.connect();

            is = connection.getInputStream();
            os = new ByteArrayOutputStream();

            final byte[] buffer = new byte[5120];
            int read;

            while (true) {
                read = is.read(buffer, 0, buffer.length);
                if (read == -1)
                    break;
                os.write(buffer, 0, read);
            }

            return os.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (is != null)
                try {
                    is.close();
                } catch (IOException ignored) {
                }
            if (os != null)
                try {
                    os.close();
                } catch (IOException ignored) {
                }
        }

        return null;
    }
}

您可以使用以下方法获取数据。

geocoderModel = geocoder.getFromLocation(latLng.latitude, latLng.longitude, 5);

您通过此代码获得了所有地址。我希望这能帮到你