In my Android app I have this code:
LatLng[] branches;
String[] branchesArray = HomeActivity.branches.toArray(new String[HomeActivity.branches.size()]);
for (int i = 0; i < HomeActivity.branches.size(); i++) {
branches[i] = getLocationFromAddress(branchesArray[i]);
}
getLocationFromAddress method:
public LatLng getLocationFromAddress(String strAddress) {
Geocoder coder = new Geocoder(this);
List<Address> address;
LatLng p1 = null;
try {
address = coder.getFromLocationName(strAddress, 1);
if (address == null) {
return null;
}
Address location = address.get(0);
location.getLatitude();
location.getLongitude();
p1 = new LatLng((double) (location.getLatitude()), (double) (location.getLongitude()));
} catch (IOException e) {
Log.e("Error", e.getMessage());
}
return p1;
}
This code supposed to create an array of LatLng, extracted from an array of string addresses. The problem is that whenever I'm running this code, I get java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0 in the log. It refers to line 137 as the problematic line, which is this line:
Address location = address.get(0);
How can I fix that?
The probleme is you are forgetting to initialize "branches" variable with the correct size that's why your are getting "size 0 index 0"
String[] branches = HomeActivity.branches.toArray(new String[HomeActivity.branches.size()]);
getLocationFromName documentation says:
returns a list of Address objects. Returns null or empty list if no
matches were found or there is no backend service available.
In your case it is returning an empty list, so you should add an additional check:
public LatLng getLocationFromAddress(String strAddress) {
Geocoder coder = new Geocoder(this);
List<Address> address;
LatLng p1 = null;
try {
address = coder.getFromLocationName(strAddress, 1);
if (address == null || address.isEmpty()) {
return null;
}
Address location = address.get(0);
p1 = new LatLng(location.getLatitude(), location.getLongitude());
} catch (IOException e) {
Log.e("Error", e.getMessage());
}
return p1;
}
Related
I was wondering if there is a better way to code this piece of code:
private void getLatitudeAndLongitudeFromZipcode() {
String zipcode = mSharedPreferences.getString("Zipcode", "");
try {
List<Address> address = geocoder.getFromLocationName(zipcode, 1);
if ((address != null ? address.size() : 0) > 0) {
Address first = address.get(0);
mLatitude = first.getLatitude();
mLongitude = first.getLongitude();
mCurrentLocationName = getLocationAsName();
mSharedPreferences.edit().putLong("oldLat", Double.doubleToRawLongBits(mLatitude))
.apply();
mSharedPreferences.edit().putLong("oldLong", Double.doubleToRawLongBits(mLongitude))
.apply();
} else {
getOldZipcodeLocation();//duplicate method call
}
} catch (IOException e) {
getOldZipcodeLocation();//duplicate method call
e.printStackTrace();
}
}
Basic idea is that if they don't have internet and an exception is thrown, I want to get the old coordinates from storage. However, I also want to get the old coordinates if they are currently in a place that doesn't give them coordinates. For example, if the geocoder returns null. What bothers me is the duplicate method call in the else block and catch block. Any way to make this code cleaner? I'll take any other tips as well!
Yes you can , 1st get address through IOException separately , then use address in your if..else statement . that's it .
private void getLatitudeAndLongitudeFromZipcode() {
String zipcode = mSharedPreferences.getString("Zipcode", "");
List<Address> address = null;
try {
address = new Geocoder(this).getFromLocationName(zipcode, 1);
} catch (IOException e) {
e.printStackTrace();
}
if ((address != null ? address.size() : 0) > 0) {
Address first = address.get(0);
mLatitude = first.getLatitude();
mLongitude = first.getLongitude();
mCurrentLocationName = getLocationAsName();
mSharedPreferences.edit().putLong("oldLat", Double.doubleToRawLongBits(mLatitude))
.apply();
mSharedPreferences.edit().putLong("oldLong", Double.doubleToRawLongBits(mLongitude))
.apply();
} else {
getOldZipcodeLocation();
}
}
In the Geocoder.java class there is the below method
public List<Address> getFromLocation(double latitude, double longitude, int maxResults)
throws IOException {
if (latitude < -90.0 || latitude > 90.0) {
throw new IllegalArgumentException("latitude == " + latitude);
}
if (longitude < -180.0 || longitude > 180.0) {
throw new IllegalArgumentException("longitude == " + longitude);
}
try {
List<Address> results = new ArrayList<Address>();
String ex = mService.getFromLocation(latitude, longitude, maxResults,
mParams, results);
if (ex != null) {
throw new IOException(ex);
} else {
return results;
}
} catch (RemoteException e) {
Log.e(TAG, "getFromLocation: got RemoteException", e);
return null;
}
}
Here getFromLocation is the member function of the class. So to call this function can't we simply call that as List<Address> address = Geocoder.getFromLocation(//the required parameters). I know this won't work and to make it work we need to create an object of Geocoder class. So can anyone please explain why the object creation is necessary, I am bit confused as I had seen in some cases functions are called by directly using their class names
Now I'm trying to get a location's country name but I cannot pass LatLng in getFromLocation().
How can I fix this?
public void checkCountry(LatLng location) {
Geocoder gcd = new Geocoder(this, Locale.getDefaut());
List<Address> addresses = gcd.getFromLocation(location.latitude, location.logtitude, 1); //error here
String country = addresses.get(0).getCountryName();
The error says
Unhandled Exception: java.IO.Exception
getFromLocation() cannot be applied to:
latitude double location.latitude
longtitude double location.longtitude
What am I wrong with this?
just handle the exception. either throw it or catch it.
public void checkCountry(LatLng location) {
Geocoder gcd = new Geocoder(this, Locale.getDefaut());
List<Address> addresses=new ArrayList<>();
try{
addresses= gcd.getFromLocation(location.latitude, location.longitude, 1); //error here
}catch (Exception e){
e.printStackTrace();
}
String country;
if(addresses!=null)if(addresses.size()!=0) country= addresses.get(0).getCountryName();
}
I want to return a string array from Async class back to the activity that is calling this asynchronous class that is job is to do the reverse geocoding.
So, from my activity I call the constructor of the class like this:
Double[] lat_long = new Double[] { Double.parseDouble(map_lat), Double.parseDouble(map_long) };
ReverseGeocodingTask reverseGeocoding = new ReverseGeocodingTask(getActivity().getApplicationContext());
reverseGeocoding.execute(lat_long);
And this is the code of the class:
class ReverseGeocodingTask extends AsyncTask<Double, Void, List<String>> {
public static List<String> LIST = new ArrayList<String>();
Context mContext;
public ReverseGeocodingTask(Context context) {
super();
mContext = context;
}
#Override
protected List<String> doInBackground(Double... params) {
Geocoder gc= new Geocoder(mContext, Locale.getDefault());
List<Address> addrList = null;
double latitude = params[0].doubleValue();
double longitude = params[1].doubleValue();
Log.d("LATLONG", latitude + ":" + longitude);
try {
addrList = gc.getFromLocation(latitude, longitude, 1);
if (addrList.size() > 0) {
//format location info
Address address = addrList.get(0);
LIST.add(address.getLocality());
LIST.add(address.getSubAdminArea());
LIST.add(address.getCountryName());
Log.d("LIST", LIST.get(0));
}
else{
Log.d("addrList SIZE", "=0");
return null;
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
return LIST;
}
#Override
protected void onPostExecute(List<String> result) {
if (result != null) {
Log.d("ON POST", result.get(0));
}
}
}
This is the logcat:
02-28 19:20:04.323 12275-14109/guide_me_for_all.guide_me_for_all D/LATLONG﹕ 34.681377999999995:33.039339
02-28 19:20:05.434 12275-14109/guide_me_for_all.guide_me_for_all D/addrList SIZE﹕ =0
I get correctly the latitude and longitude point as you can see from the Log.d(), BUT getFromLocation.size() is always 0.
This may be a problem with your GeoCoder service. If you're backend service for the device is not present or has other problems, you will get this response.
use isPresent to check if an implementation is present.
Also, see this post here:
Geocoder.getFromLocation throws IOException on Android emulator
And the docs mention that you need a backend service:
http://developer.android.com/reference/android/location/Geocoder.html
I want to get photos and place_id required by Google Place Details API of my current location.
Search nearby does not return places in my exact location. (current lat/lng returned by android location service).
Radar search requires a keyword. Please suggest.
Per the Google Place Search documentation the three things you need to provide are the KEY, LOCATION and RADIUS. I cut out a bunch of unnecessary code, but here's how I did something similar.
1) Get your current location
private void initializeMapLocation() {
LocationManager locationManager = (LocationManager) this
.getSystemService(Context.LOCATION_SERVICE);
Location lastLocation = locationManager
.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (lastLocation != null) {
setUserLocation(lastLocation);
}
}
private void setUserLocation(Location location) {
LatLng currentLatLng = new LatLng(location.getLatitude(), location.getLongitude());
mMap.animateCamera(CameraUpdateFactory.newLatLng(currentLatLng));
}
2) Build your search URL. You can add extra parameters like a keyword if you want by appending them on, but it doesn't sound like you want that in this particular case.
private void buildAndInitiateSearchTask(String searchType) {
Projection mProjection = mMap.getProjection();
LatLng mProjectionCenter = mProjection.getVisibleRegion().latLngBounds
.getCenter();
searchURL.append("https://maps.googleapis.com/maps/api/place/nearbysearch/");
searchURL.append("json?");
searchURL.append("location=" + mProjectionCenter.latitude + "," + mProjectionCenter.longitude);
searchURL.append("&radius=" + calculateProjectionRadiusInMeters(mProjection));
searchURL.append("&key=YOUR_KEY_HERE");
new PlaceSearchAPITask().execute(searchURL.toString());
}
private double calculateProjectionRadiusInMeters(Projection projection) {
LatLng farLeft = projection.getVisibleRegion().farLeft;
LatLng nearRight = projection.getVisibleRegion().nearRight;
Location farLeftLocation = new Location("Point A");
farLeftLocation.setLatitude(farLeft.latitude);
farLeftLocation.setLongitude(farLeft.longitude);
Location nearRightLocation = new Location("Point B");
nearRightLocation.setLatitude(nearRight.latitude);
nearRightLocation.setLongitude(nearRight.longitude);
return farLeftLocation.distanceTo(nearRightLocation) / 2 ;
}
3) Send your request and display your results as an AsyncTask
private class PlaceSearchAPITask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... placesURL) {
StringBuilder placesBuilder = new StringBuilder();
for (String placeSearchURL : placesURL) {
HttpClient placesClient = createHttpClient();
try {
HttpGet placesGet = new HttpGet(placeSearchURL);
HttpResponse placesResponse = placesClient
.execute(placesGet);
StatusLine placeSearchStatus = placesResponse
.getStatusLine();
if (placeSearchStatus.getStatusCode() == 200) {
HttpEntity placesEntity = placesResponse
.getEntity();
InputStream placesContent = placesEntity
.getContent();
InputStreamReader placesInput = new InputStreamReader(
placesContent);
BufferedReader placesReader = new BufferedReader(
placesInput);
String lineIn;
while ((lineIn = placesReader.readLine()) != null) {
placesBuilder.append(lineIn);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
return placesBuilder.toString();
}
#Override
protected void onPostExecute(String result) {
try {
JSONObject resultObject = new JSONObject(result);
// This is my custom object to hold the pieces of the JSONResult that I want. You would need something else for your particular problem.
mapData = new MapDataSource(resultObject.optJSONArray("results"));
} catch (JSONException e) {
e.printStackTrace();
}
if (mapData != null) {
// TODO - This is where you would add your markers and whatnot.
}
}
}