Android geocoding not functioning as well as iOS - java

So I have a function for converting an address (String) into coordinates.
This is what it looks like in iOS:
func setCoords(buildet: BuildingDetail) {
let geoCoder = CLGeocoder()
geoCoder.geocodeAddressString(buildet.address, completionHandler:
{(placemarks: [AnyObject]!, error: NSError!) in
if error != nil {
println("Geocode failed with error: \(error.localizedDescription)")
} else if placemarks.count > 0 {
let placemark = placemarks[0] as! CLPlacemark
let location = placemark.location
buildet.lat = location.coordinate.latitude
buildet.lon = location.coordinate.longitude
}
self.setupMarker(buildet)
})
}
This is what it looks like in Android:
public static double[] getLatLongPositions(String address) throws Exception
{
int responseCode = 0;
String api = "http://maps.googleapis.com/maps/api/geocode/xml?address=" + URLEncoder.encode(address, "UTF-8") + "&sensor=true";
System.out.println("URL : "+api);
URL url = new URL(api);
HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection();
httpConnection.connect();
responseCode = httpConnection.getResponseCode();
if(responseCode == 200)
{
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();;
Document document = builder.parse(httpConnection.getInputStream());
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile("/GeocodeResponse/status");
String status = (String)expr.evaluate(document, XPathConstants.STRING);
if(status.equals("OK"))
{
expr = xpath.compile("//geometry/location/lat");
String latitude = (String)expr.evaluate(document, XPathConstants.STRING);
expr = xpath.compile("//geometry/location/lng");
String longitude = (String)expr.evaluate(document, XPathConstants.STRING);
return new double[] {Double.parseDouble(latitude), Double.parseDouble(longitude)};
}
}
return new double[]{0,0};
}
Now, the iOS function above just runs the setupMarker function, where the Android method returns the coordinates, no big deal!
The problem I have is, I am supplying both functions with the exact same address arguments.
iOS returns all the coordinates perfectly.
Whereas, Android only returns around 30% of them properly.
Is there an Android function equivalent to the iOS one above, or just one that can geocode properly.
As you can see the Android calls the API here:
http://maps.googleapis.com/maps/api/geocode/xml?address=
And I have tested this, it doesn't give good results, at least not as good as iOS.
What can I do about it?
EDIT - Some Examples (All work with iOS)
EBS, 2 Burlington Road, Dublin 2
AIB Bankcentre, Merrion Road, Ballsbridge, Dublin 4, Ireland
AIB, Unit 33, Sandyford Business Centre, Sandyford, Dublin 18

Try using a URL that returns data in JSON format, which you can then parse and get the latitude and longitude. Here is an example:
public static void getLatLongFromAddress(String youraddress) {
String uri = "http://maps.google.com/maps/api/geocode/json?address=" +
youraddress + "&sensor=false";
HttpGet httpGet = new HttpGet(uri);
HttpClient client = new DefaultHttpClient();
HttpResponse response;
StringBuilder stringBuilder = new StringBuilder();
try {
response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
InputStream stream = entity.getContent();
int b;
while ((b = stream.read()) != -1) {
stringBuilder.append((char) b);
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
JSONObject jsonObject = new JSONObject();
try {
jsonObject = new JSONObject(stringBuilder.toString());
double lng = ((JSONArray)jsonObject.get("results")).getJSONObject(0)
.getJSONObject("geometry").getJSONObject("location")
.getDouble("lng");
double lat = ((JSONArray)jsonObject.get("results")).getJSONObject(0)
.getJSONObject("geometry").getJSONObject("location")
.getDouble("lat");
Log.d("latitude", "" + lat);
Log.d("longitude", "" + lng);
} catch (JSONException e) {
e.printStackTrace();
}
}
Hope this helps.

Related

How to return JSON response from a URL returning HTML

First, some background :-
I'm trying to solve a question asked by an interviewer recently. I had to write a code and use below URL to return JSON response -
https://losangeles.craigslist.org/
This is what I did :-
1) I created a webclient and made HTTPURL Request to fetch an HTTP Response.
public static JSONArray getSearchResults(String arg) {
JSONArray jsonArray = null;
try {
QueryString qs = new QueryString("query", arg);
URL url = new URL("https://toronto.craigslist.ca/search?"+qs);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/text");
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ conn.getResponseCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
String readAPIResponse = " ";
StringBuilder output = new StringBuilder();
while ((readAPIResponse = br.readLine()) != null) {
output.append(readAPIResponse);
}
jsonArray = convertToJson(output);
System.out.println(" JSON response : "+jsonArray.toString(2));
conn.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return jsonArray;
}
2) Below was my function to convert the response into JSON :-
public static JSONArray convertToJson(StringBuilder response) {
JSONArray jsonArr = new JSONArray();
if (response != null) {
try {
Document document = Jsoup.parse(response.toString());
Elements resultRows = document.getElementsByClass("result-row");
JSONObject jsonObj;
for (int i = 0; i < resultRows.size(); i++) {
jsonObj = new JSONObject();
Element e = resultRows.get(i);
Elements resultsDate = e.getElementsByClass("result-date");
Elements resultsTitle = e.getElementsByClass("result-title hdrlnk");
String key1 = "date";
String value1 = resultsDate.get(0).text();
jsonObj.put(key1, value1);
String key2 = "title";
String value2 = resultsTitle.get(0).text();
jsonObj.put(key2, value2);
jsonArr.put(i, jsonObj);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return jsonArr;
}
The response I received was the whole HTML page(I used postman to make requests). Since, I only had few hours to solve this question and was not sure how to parse an entire HTML, I ended up using a third party library, called JSoup. I was not 100% happy about it, but ended up having no other option.
I have not heard back from them and I am curious if this was the worst approach and if yes, what could be better options? They did not mention anything about what technology I could use. But,since the skill set I was interviewing involved Java/J2EE I was thinking to implement this in Java (Not using Node js though)
Thanks!
If you only need an XML Parser which is obviously the base of HTML this is built in in the JRE core API.
Even in the SE Version the needed packages to parse exist:
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.*;
Take a look at these classes they are the most important to parse or create an XML/HTML File
DocumentBuilderFactory
DocumentBuilder
Document
and here simple example for HTML
String text = "<html><head>HEAD</head><body>BODY</body>";
ByteArrayInputStream input = new ByteArrayInputStream(text.getBytes("UTF-8"));
Document doc = builder.parse(input);

PDF Reading using PDF box - Clarification with page count

Read a pdf file from url with using of PDFbox, below jave code its perfect to read a pdf and stored in project location.
String pdfPageCount = 17;
String pdfUrl = "abc.org/invoicepdf.pdf?Range=1";
URL pdfDownload = new URL(pdfUrl);
connectionGet = (HttpsURLConnection) pdfDownload.openConnection();
String authorizationHeader1 = "Bearer " + getToken;
connectionGet.setRequestProperty("Authorization", authorizationHeader1);
connectionGet.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connectionGet.setRequestMethod("GET");
int responseCode = connectionGet.getResponseCode();
if (responseCode != 404) {
PDDocument pd = new PDDocument();
InputStream inputstreamFinal1 = connectionGet.getInputStream();
PDDocument load = PDDocument.load(inputstreamFinal1);
load.save("CopyOfInvoice1.pdf");
}
My next step
I want to looping the process based on the pdfPageCount value, currently i do hard-coded the page count in 1 in the pdfUrl (/invoicepdf.pdf?Range=1)
Expected:
Read all the 17 pages and save into an single pdf file
Here's some code, based on the PDFMergerExample that is mentioned in the comments. Note that I haven't checked if your URL retrieval code is correct.
List<InputStream> sources = new ArrayList<InputStream>();
int pdfPageCount = 17;
try
{
for (int p = 1; p <= pdfPageCount; ++p)
{
String pdfUrl = "abc.org/invoicepdf.pdf?Range=" + p;
URL pdfDownload = new URL(pdfUrl);
HttpsURLConnection connectionGet = (HttpsURLConnection) pdfDownload.openConnection();
String authorizationHeader1 = "Bearer " + getToken;
connectionGet.setRequestProperty("Authorization", authorizationHeader1);
connectionGet.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connectionGet.setRequestMethod("GET");
int responseCode = connectionGet.getResponseCode();
if (responseCode != 404)
{
sources.add(connectionGet.getInputStream());
}
else
{
//TODO error handling
return;
}
}
PDFMergerUtility pdfMerger = new PDFMergerUtility();
pdfMerger.addSources(sources);
pdfMerger.setDestinationFileName("CopyOfInvoice1.pdf");
pdfMerger.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
}
catch (IOException e)
{
//TODO error handling
return;
}
finally
{
// cleanup
for (InputStream source : sources)
{
IOUtils.closeQuietly(source);
}
}

getting a null pointer exception when trying to parse JSON data from a url in a Async Class android

Could someone please explain or correct as to why I am getting a null pointer exception in my Async Class? I am trying to get data from a URL but get a null pointer exception for the 162, which contains the following code
int lengthJsonArr = jsonMainNode.length();
I am not sure as to why that is but if someone could help that would be great. or if someone can show me a better alternative to fetch json data from url that would also be a great help.
public class userTask extends AsyncTask<String, Void, Void>{
HttpURLConnection connection = null;
private String Content;
#Override
protected Void doInBackground(String... urls) {
BufferedReader reader = null;
try {
URL url = new URL(urls[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
} Content = buffer.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(Void s) {
super.onPostExecute(s);
String OutputData = "";
JSONObject jsonResponse;
try {
jsonResponse = new JSONObject(Content);
JSONArray jsonMainNode = jsonResponse.optJSONArray("Android");
int lengthJsonArr = jsonMainNode.length(); //This is causing the exception
for (int i =0; i < lengthJsonArr; i++) {
JSONObject jsonChildNode = jsonMainNode.getJSONObject(i);
String name = jsonChildNode.optString("name").toString();
Double longitude = jsonChildNode.optDouble("lon");
Double latitude = jsonChildNode.optDouble("lat");
OutputData += " Name : "+ name +" "
+ "Longitude : "+ longitude +" "
+ "Latitude : "+ latitude +" "
+"-------------------------------------------------- ";
//Show Parsed Output on screen (activity)
Toast toast = Toast.makeText(getApplicationContext(), OutputData, Toast.LENGTH_LONG);
toast.show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
This is not a good way to fetch JSON data in android. You should use Volley or Retrofit library. These libraries will work accuratly and efficiently than normal code.
There are alot of things to take care of while fetching data. All will be done by library. And you just need to write few lines of code.
You can follow many good tutorials on google.
As this works...
jsonResponse = new JSONObject(Content);
...you at least succesfully receive a HTTP response which contains a valid JSON object.
The next line...
JSONArray jsonMainNode = jsonResponse.optJSONArray("Android");
...tries to extract a JSON array, but apparently fails and as a result your jsonMainNode variable is null. That is how optJSONArray() works. It just returns null if it does not find what was asked for. (Instead of throwing a JSONException for example.)
Then the next line...
int lengthJsonArr = jsonMainNode.length();
...of course fails because you can't get the length of a null JSON array.
So it looks like the JSON you receive does not include an array called "Android". You could/should place a breakpoint on...
JSONArray jsonMainNode = jsonResponse.optJSONArray("Android");
...and check what's in the JSON object. Or just print out the response. (And properly name it "content" with lowercase so people won't nag about the Java coding convention...)
As for avoiding the NullPointerException you could use code like:
if (jsonResponse.has("Android")) {
JSONArray jsonMainNode = jsonResponse.optJSONArray("Android");
int lengthJsonArr = jsonMainNode.length();
// Etc.
// ...
}
else {
// TODO: Recover from the situation.
// ...
}

Restrict the AutoCompleteTextView predictions to only restaurants

I've got an Android app that allows the user to perform a details search based on a restaurants name. However, depending on the users input, the predictions can contain places, countries, etc. Where can I add a restriction to only check for restaurant names?
My current code:
public static ArrayList<String> autocomplete(String input) {
ArrayList<String> resultList = null;
HttpURLConnection conn = null;
StringBuilder jsonResults = new StringBuilder();
try {
StringBuilder sb = new StringBuilder(PLACES_API_BASE
+ TYPE_AUTOCOMPLETE + OUT_JSON);
sb.append("?key=" + API_KEY);
sb.append("&input=" + URLEncoder.encode(input, "utf8"));
URL url = new URL(sb.toString());
System.out.println("URL: " + url);
conn = (HttpURLConnection) url.openConnection();
InputStreamReader in = new InputStreamReader(conn.getInputStream());
// Load the results into a StringBuilder
int read;
char[] buff = new char[1024];
while ((read = in.read(buff)) != -1) {
jsonResults.append(buff, 0, read);
}
} catch (MalformedURLException e) {
Log.e(LOG_TAG, "Error processing Places API URL", e);
return resultList;
} catch (IOException e) {
Log.e(LOG_TAG, "Error connecting to Places API", e);
return resultList;
} finally {
if (conn != null) {
conn.disconnect();
}
}
try {
// Create a JSON object hierarchy from the results
JSONObject jsonObj = new JSONObject(jsonResults.toString());
JSONArray predsJsonArray = jsonObj.getJSONArray("predictions");
resultList = new ArrayList<String>(predsJsonArray.length());
place = new HashMap<String, String>();
for (int i = 0; i < predsJsonArray.length(); i++) {
// System.out.println(predsJsonArray.getJSONObject(i).getString(
// "description"));
// System.out
// .println("============================================================");
resultList.add(predsJsonArray.getJSONObject(i).getString(
"description"));
String description = predsJsonArray.getJSONObject(i).getString("description");
String placeId = predsJsonArray.getJSONObject(i).getString("place_id");
place.put( description, placeId);
}
} catch (JSONException e) {
Log.e(LOG_TAG, "Cannot process JSON results", e);
}
return resultList;
}
According to place types the closest you can get is the establishment filter. You are going to have to perform a search rather than an autocomplete in order to use the restaurant filter.
Using the Places API for Android PlaceComplete sample I tried passing in Place.TYPE_ESTABLISHMENT and Place.TYPE_RESTAURANT to AutocompleteFilter.create to verify.
Try adding a place_type in your search, use this link to find the supported types.

how to get a value by key from an json (or xml) string?

In the android app I get an xml or json string returned, However, I cant seem to figure out any way on how to get an value from the string in any way by entering an key.
In PHP you just use something like $myArray['parent']['child'] but I have no clue on how this works in java.
Any idea's would be greatly appreciated! (an example for both XML and JSON even more ;) )
Here's what I would do:
locate an XML/JSON library (there's tons) (google-gson for json)
read the documentation to find a parse method ((new JsonParser()).parse(text))
read the documentation to find out what the return value is (JsonElement)
decide what you want to do with the parsed data (myJsonObj.get(...))
write the code
public class parsingjsontest2 extends Activity {
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(main);
String str = connect("http://rentopoly.com/ajax.php?query=Bo"));
System.out.println("String::"+str);
}
}
private String connect(String url)
{
// Create the httpclient
HttpClient httpclient = new DefaultHttpClient();
// Prepare a request object
HttpGet httpget = new HttpGet(url);
// Execute the request
HttpResponse response;
// return string
String returnString = null;
try {
// Open the webpage.
response = httpclient.execute(httpget);
if(response.getStatusLine().getStatusCode() == 200){
// Connection was established. Get the content.
HttpEntity entity = response.getEntity();
// If the response does not enclose an entity, there is no need
// to worry about connection release
if (entity != null) {
// A Simple JSON Response Read
InputStream instream = entity.getContent();
// Load the requested page converted to a string into a JSONObject.
JSONObject myAwway = new JSONObject(convertStreamToString(instream));
// Get the query value'
String query = myAwway.getString("query");
**// Make array of the suggestions
JSONArray suggestions = myAwway.getJSONArray("suggestions");
// Build the return string.
returnString = "Found: " + suggestions.length() + " locations for " + query;
for (int i = 0; i < suggestions.length(); i++) {
returnString += "\n\t" + suggestions.getString(i);
}
// Cose the stream.
instream.close();
}
}
else {
// code here for a response othet than 200. A response 200 means the webpage was ok
// Other codes include 404 - not found, 301 - redirect etc...
// Display the response line.
returnString = "Unable to load page - " + response.getStatusLine();
}
}
catch (IOException ex) {
// thrown by line 80 - getContent();
// Connection was not established
returnString = "Connection failed; " + ex.getMessage();
}
catch (JSONException ex){
// JSON errors
returnString = "JSON failed; " + ex.getMessage();
}
return returnString;
}
private static String convertStreamToString(InputStream is) {
/*
* To convert the InputStream to String we use the BufferedReader.readLine()
* method. We iterate until the BufferedReader return null which means
* there's no more data to read. Each line will appended to a StringBuilder
* and returned as String.
*/
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
}
As you didn't specify what kind of xml you are trying to read, I'm answering based on what I know.
In Android, if you were talking about the layout and strings.xml files, you use a dot (.) operator, like R.string.appname.
Please post more details about your specific problem, if this is not what you were looking for.

Categories

Resources