I just started learning the Android platform. I find that the best way to learn something is just diving in. It's my first time using Java as a language. It seems pretty familiar since I've done a bit of Processing and JavaScript, but throw in an SDK and it can get down right confusing. I had this idea for an app and it was basically a Google mashup. Naively, I thought that everything Google has to offer would be baked in. Not so much for the Google Places API. Using Places on the web is stupid easy so I was a bit disappointed when I wanted to incorporate that autocomplete into my app. Searching the interwebs, I was able to piece it together but I was really surprised that a tutorial for this specific example doesn't exist. The following code will show an editable textfield that will dynamically update the autocomplete list based on JSON from the Google Places API. So here we go...
First things first, in your XML layout you need to put an AutoCompleteTextField.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#dddddd">
<AutoCompleteTextView android:id="@+id/autoCompleteTextView1" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_below="@+id/textView1" android:layout_alignLeft="@+id/textView2" android:layout_marginTop="10dp" android:layout_alignRight="@+id/mapButton">
<requestFocus></requestFocus>
</AutoCompleteTextView>
</RelativeLayout>Your AutoCompleteTextField likes a layout file for the items, so go ahead and add an XML flle to called item_list.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp"
android:textSize="16sp"
android:textColor="#000">
</TextView>The AutoCompleteTextField needs an ArrayAdapter for the list, so when in the OnCreate method we declare it and put some initial data in it. Here are the important parts in your java file:
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.list_item);
AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView1);
adapter.setNotifyOnChange(true);
textView.setAdapter(adapter);The code above declares the ArrayAdapter and points it to the item_list.xml file for styling. Then we declare textView and reference the AutoCompleteTextField in our XML layout. Since we want to get updates, we tell the adapter to notify on changes. Last but not least, we set the adapter for our AutoCompleteTextField to the ArrayAdapter we created.
Right below that, we setup our text watcher. This will run every time the text changes. This is pretty crude on my part, but to limit the amount of calls to the webservice, I'm checking every 3 characters. Inside the textwatcher, we call out to the Google Places service.
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (count%3 == 1) {
//we don't want to make an insanely large array, so we clear it each time
adapter.clear();
}
Inside of the textwatcher, we do the actual JSON parsing. Here's that code:
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=fr&sensor=true&key=<yourapikeygoeshere>");
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
adapter.add(jo.getString("description"));
}
You might notice there's some trickery there with JSONArray and JSONObject. I found this tutorial for parsing the public twitter feed. After scratching my head a bit on why that code wouldn't automagically work with Google's JSON I realized two things: Twitter gives you just one garbled line of JSON (which is fine for machines) while Google gives you beautiful multiline JSON (great for humans) and second, the Twitter feed is an array of objects, while Google Places returns an object with an array.
For those of you who like cutting and pasting, here's the whole thing:
package com.yourco.yourapp;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
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;
public class Main extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.list_item);
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();
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=fr&sensor=true&key=<getyourowndamnkey>");
URLConnection tc = googlePlaces.openConnection();
Log.d("GottaGo", URLEncoder.encode(s.toString()));
BufferedReader in = new BufferedReader(new InputStreamReader(
tc.getInputStream()));
String line;
StringBuffer sb = new StringBuffer();
while ((line = in.readLine()) != null) {
sb.append(line);
}
JSONObject predictions = new JSONObject(sb.toString());
JSONArray ja = new JSONArray(predictions.getString("predictions"));
for (int i = 0; i < ja.length(); i++) {
JSONObject jo = (JSONObject) ja.get(i);
adapter.add(jo.getString("description"));
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
public void afterTextChanged(Editable s) {
}
});
}
Comments
If my problem was a Death
Prudy - November 15, 2011If my problem was a Death Star, this article is a photon toperdo.
Heck of a job there, it
Keyanna - November 16, 2011Heck of a job there, it absluotely helps me out.
Add new comment