google distance matrix with autocomplete on android-Collection of common programming errors
I am trying to do what the header is saying, which is to create an app with google distance matrix with autocomplete on android. So far, with my research and studying on the books myself, it is very difficult to come up with the code and I finally reach out here. So far I have gone to
https://developers.google.com/maps/documentation/distancematrix/#Introduction
and google directions document
http://www.claytical.com/blog/android-dynamic-autocompletion-using-google-places-api http://www.stackoverflow.com/questions/9142885/geocoder-autocomplete-in-android http://www.stackoverflow.com/questions/6456090/android-google-map-finding-distance/6456161#6456161
All these links have not really helped me understand it and I do understand the concept of Requesting to the API address and it returning the JSON and I have to “Parse” the JSON and extract the necessary information, which is the distance in my case. but what I do not get is how I can create an autocomplete that has suggestion from the google maps distance matrix and also how I can send the origin and destination accordingly. It is really frustrating and this is what I have from the Claytical.com.
Here’s the main.java
package com.example.autocomplete;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
public class Main extends Activity {
/** Called when the activity is first created. */
public ArrayAdapter adapter;
public AutoCompleteTextView textview;
public Object s;
class GetPlaces extends AsyncTask
{
public ArrayAdapter adapter;
public AutoCompleteTextView textview;
Object s;
@Override
// three dots is java for an array of strings
protected ArrayList doInBackground(String... args)
{
Log.d("gottaGo", "doInBackground");
ArrayList predictionsArr = new ArrayList();
try
{
URL googlePlaces = new URL(
// URLEncoder.encode(url,"UTF-8");
"https://maps.googleapis.com/maps/api/place/autocomplete/json?input="+ URLEncoder.encode(s.toString(), "UTF-8") +"&types=geocode&language=en&sensor=true&key=");
URLConnection tc = googlePlaces.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(
tc.getInputStream()));
String line;
StringBuffer sb = new StringBuffer();
//take Google's legible JSON and turn it into one big string.
while ((line = in.readLine()) != null) {
sb.append(line);
}
//turn that string into a JSON object
JSONObject predictions = new JSONObject(sb.toString());
//now get the JSON array that's inside that object
JSONArray ja = new JSONArray(predictions.getString("predictions"));
for (int i = 0; i < ja.length(); i++) {
JSONObject jo = (JSONObject) ja.get(i);
//add each entry to our array
predictionsArr.add(jo.getString("description"));
}
} catch (IOException e)
{
Log.e("YourApp", "GetPlaces : doInBackground", e);
} catch (JSONException e)
{
Log.e("YourApp", "GetPlaces : doInBackground", e);
}
return predictionsArr;
}
//then our post
@Override
protected void onPostExecute(ArrayList result)
{
Log.d("YourApp", "onPostExecute : " + result.size());
//update the adapter
ArrayAdapter adapter = new ArrayAdapter(getBaseContext(), R.layout.item_list);
adapter.setNotifyOnChange(true);
//attach the adapter to textview
textview.setAdapter(adapter);
for (String string : result)
{
Log.d("YourApp", "onPostExecute : result = " + string);
adapter.add(string);
adapter.notifyDataSetChanged();
}
Log.d("YourApp", "onPostExecute : autoCompleteAdapter" + adapter.getCount());
}
private Context getBaseContext() {
// TODO Auto-generated method stub
return null;
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final ArrayAdapter adapter = new ArrayAdapter(this,R.layout.item_list);
final AutoCompleteTextView textView = (AutoCompleteTextView)
findViewById(R.id.autoCompleteTextView1);
adapter.setNotifyOnChange(true);
textView.setAdapter(adapter);
textView.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (count%3 == 1) {
adapter.clear();
GetPlaces task = new GetPlaces();
//now pass the argument in the textview to the task
task.execute(textView.getText().toString());
}
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
public void afterTextChanged(Editable s) {
}
});
}
}
and my main.xml
Lastly, here’s LOGCAT as requested.
05-14 17:41:38.163: E/Trace(1390): error opening trace file: No such file or directory (2)
05-14 17:41:39.323: D/gralloc_goldfish(1390): Emulator without GPU emulation detected.
05-14 17:41:45.284: D/gottaGo(1390): doInBackground
05-14 17:41:45.296: W/dalvikvm(1390): threadid=11: thread exiting with uncaught exception (group=0x40a13300)
05-14 17:41:45.314: E/AndroidRuntime(1390): FATAL EXCEPTION: AsyncTask #1
05-14 17:41:45.314: E/AndroidRuntime(1390): java.lang.RuntimeException: An error occured while executing doInBackground()
05-14 17:41:45.314: E/AndroidRuntime(1390): at android.os.AsyncTask$3.done(AsyncTask.java:299)
05-14 17:41:45.314: E/AndroidRuntime(1390): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
05-14 17:41:45.314: E/AndroidRuntime(1390): at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
05-14 17:41:45.314: E/AndroidRuntime(1390): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
05-14 17:41:45.314: E/AndroidRuntime(1390): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
05-14 17:41:45.314: E/AndroidRuntime(1390): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
05-14 17:41:45.314: E/AndroidRuntime(1390): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
05-14 17:41:45.314: E/AndroidRuntime(1390): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
05-14 17:41:45.314: E/AndroidRuntime(1390): at java.lang.Thread.run(Thread.java:856)
05-14 17:41:45.314: E/AndroidRuntime(1390): Caused by: java.lang.NullPointerException
05-14 17:41:45.314: E/AndroidRuntime(1390): at com.example.autocomplete.Main$GetPlaces.doInBackground(Main.java:54)
05-14 17:41:45.314: E/AndroidRuntime(1390): at com.example.autocomplete.Main$GetPlaces.doInBackground(Main.java:1)
05-14 17:41:45.314: E/AndroidRuntime(1390): at android.os.AsyncTask$2.call(AsyncTask.java:287)
05-14 17:41:45.314: E/AndroidRuntime(1390): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
05-14 17:41:45.314: E/AndroidRuntime(1390): ... 5 more
05-14 17:41:47.584: I/Choreographer(1390): Skipped 31 frames! The application may be doing too much work on its main thread.
05-14 17:41:47.904: I/Process(1390): Sending signal. PID: 1390 SIG: 9
It launches just fine and it brings up the auto complete textview but as soon as I type a letter, it crashes. Thanks for reading this far and Thank you in advance for your help!
-
OK first thing is that your URL is malformed:
https://maps.googleapis.com/maps/api/place/autocomplete/json?input=" + URLEncoder.encode(s.toString(), "UTF-8") + "&types=geocode&language=en&sensor=true&key=
You need to replace with your API key for it to work. Next thing is how you form your JSON array. You need to replace
JSONArray ja = new JSONArray(predictions.getString("predictions"));
with
JSONArray ja = new JSONArray(predictions.getJSONArray("predictions"));
Next in your loop, replace
JSONObject jo = (JSONObject) ja.get(i);
with
JSONObject jo = ja.getJSONObject(i);
Try this and let me know how it goes.