1

I have an autocomplete adapter for my app and I am getting back json results from the Google Places API. My trouble is with trying to get the results to display on the screen. I am using this guide: http://examples.javacodegeeks.com/android/android-google-places-autocomplete-api-example/

For the most part the code seems sound, but for whatever reason I can't get anything to print out onto my display. I don't really understand how the filter works, and maybe an explanation for how that works with the autocomplete adapter would help.

My onCreate is:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        buildGoogleApiClient();
        setContentView(R.layout.activity_maps);
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);

        if (savedInstanceState != null) {
            mIsResolving = savedInstanceState.getBoolean(KEY_IS_RESOLVING);
            mShouldResolve = savedInstanceState.getBoolean(KEY_SHOULD_RESOLVE);
        }

//      Create the LocationRequest object
        mLocationRequest = LocationRequest.create()
                .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
                .setInterval(10 * 1000)           //10 seconds, in milliseconds
                .setFastestInterval(1 * 1000);   //1 second, in milliseconds

        Log.d(TAG, "GoogleApiClient built");

        if (savedInstanceState != null) {
            mSignInProgress = savedInstanceState
                    .getInt(SAVED_PROGRESS, STATE_DEFAULT);
        }

        mShouldResolve = true;
        mGoogleApiClient.connect();
        Log.d(TAG, "Starting sign-in");



        AutoCompleteTextView autoCompView = (AutoCompleteTextView)
                findViewById(R.id.autoCompleteTextView);


        autoCompView.setAdapter(new GooglePlacesAutocompleteAdapter(this, R.layout.activity_maps));
        autoCompView.setOnItemClickListener(this);

    }

My method for getting the Json results is:

public ArrayList<String> autocomplete(String input) {
        Log.d(TAG, "performSearch()");

        ArrayList resultList = null;

        AsyncTask<ArrayList<String>, Void, ArrayList>
                myTask = new AsyncTask<ArrayList<String>, Void, ArrayList>() {

            AutoCompleteTextView text = (AutoCompleteTextView)
                    findViewById(R.id.autoCompleteTextView);
            private String input = text.getText().toString();

            @Override
            protected ArrayList doInBackground(ArrayList<String>... params) {
                Log.d(TAG, "Starting Search");

                ArrayList resultList = null;

                HttpURLConnection conn = null;
                StringBuilder jsonResults = new StringBuilder();
                try {
                    KEYWORD = input;

                    ENDPOINT = Uri
                            .parse("https://maps.googleapis.com/maps/api/place/nearbysearch/json")
                            .buildUpon()
                            .appendQueryParameter("location", LOCATION)
                            .appendQueryParameter("radius", "10000")
                            .appendQueryParameter("keyword", KEYWORD)
                            .appendQueryParameter("key", API_KEY)
                            .build();

                    URL url = new URL(ENDPOINT.toString());

                    Log.d(TAG, "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);
                    }
                    Log.d(TAG, jsonResults.toString());
                } catch (MalformedURLException e) {
                    Log.e(TAG, "Error processing Places API URL", e);
                    return resultList;
                } catch (IOException e) {
                    Log.e(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("results");

                    // Extract the Place descriptions from the results
                    resultList = new ArrayList(predsJsonArray.length());
                    for (int i = 0; i < predsJsonArray.length(); i++) {
                        System.out.println(predsJsonArray.getJSONObject(i).getString("name"));
                        System.out.println(predsJsonArray.getJSONObject(i).getString("vicinity"));
                        System.out.println("=====================================================");
                        resultList.add(predsJsonArray.getJSONObject(i).getString("name"));
                        resultList.add(predsJsonArray.getJSONObject(i).getString("vicinity"));
                    }
                } catch (JSONException e) {
                    Log.e(TAG, "Cannot process JSON results", e);
                }
                Log.d(TAG, resultList.toString());
                return resultList;
            }

        };

        myTask.execute();

        Log.d(TAG, resultList.toString());
        return resultList;
    }

My filter class is:

class GooglePlacesAutocompleteAdapter extends ArrayAdapter implements Filterable {
        private ArrayList resultList;

        public GooglePlacesAutocompleteAdapter(Context context, int textViewResourceId) {
            super(context, textViewResourceId);
        }

        @Override
        public int getCount() {
            return resultList.size();
        }

        @Override
        public String getItem(int index) {
            return (String) resultList.get(index);
        }

        @Override
        public Filter getFilter() {
            Filter filter = new Filter() {
                @Override
                protected FilterResults performFiltering(CharSequence constraint) {
                    FilterResults filterResults = new FilterResults();
                    if (constraint != null) {
                        // Retrieve the autocomplete results.
                         resultList = autocomplete(constraint.toString());

                        // Assign the data to the FilterResults
                        filterResults.values = resultList;
                        filterResults.count = resultList.size();
                    }
                    return filterResults;
                }

                @Override
                protected void publishResults(CharSequence constraint, Filter.FilterResults results) {
                    if (results != null && results.count > 0) {
                        notifyDataSetChanged();
                    } else {
                        notifyDataSetInvalidated();
                    }
                }
            };
            return filter;
        }
    }

I know I'm getting a sound result back from google and my built array looks like this (it includes both name and vicinity):

[Midtown Global Market, 920 East Lake Street #G10, Minneapolis, The Anchor Fish & Chips, 302 13th Avenue Northeast, Minneapolis, Brasa Premium Rotisserie, 600 East Hennepin Avenue, Minneapolis, Wedge Community Co-Op, 2105 Lyndale Avenue South, Minneapolis, Tao Natural Foods, 2200 Hennepin Avenue, Minneapolis, Fresh & Natural Foods, 1075 Highway 96 West, Saint Paul, Whole Foods Market, 222 Hennepin Avenue, Minneapolis, Sen Yai Sen Lek Thai, 2422 Central Avenue Northeast, Minneapolis, Mississippi Market Natural Foods Co-op, 622 Selby Avenue, Saint Paul, Eastside Food Co-Op, 2551 Central Avenue Northeast, Minneapolis, Bills Imported Foods, 721 West Lake Street, Minneapolis, Seoul Foods, 1071 East Moore Lake Drive, Minneapolis, Seward Community Co-op - Franklin Store, 2823 East Franklin Avenue, Minneapolis, Foxy Falafel, 791 Raymond Avenue, Saint Paul, Asian Foods, 1300 L'Orient Street, Saint Paul, Pohl Distributing Co, 510 Kasota Avenue Southeast, Minneapolis, Rainbow Foods, 1566 University Avenue West, Saint Paul, Dandelion Kitchen Truck, 800 Nicollet Mall, Minneapolis, World Street Kitchen, 2743 Lyndale Avenue South #5, Minneapolis, CES Food Shelf, East 19th Street, Minneapolis]

Any help is appreciated, thanks!

[EDIT] Here is my XML for activity_maps:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                 xmlns:tools="http://schemas.android.com/tools"
                 android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context="com.hudsoncorp.zahudson.roadtrip.MapsActivity">

        <fragment xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            xmlns:map="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/map"
            tools:context="com.hudsoncorp.zahudson.roadtrip.MapsActivity"
            android:name="com.google.android.gms.maps.SupportMapFragment"/>

        <RelativeLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="10dp">

            <AutoCompleteTextView
                android:id="@+id/autoCompleteTextView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:hint="Search location"
                android:background="#FFFFFF"
                android:textColor="#00000F"
                      android:theme="@android:style/Widget.Material.AutoCompleteTextView"
                android:ems="10"
                android:shadowColor="@color/background_floating_material_dark">
                <requestFocus />

            </AutoCompleteTextView>

        </RelativeLayout>

</RelativeLayout>
zahudson95
  • 57
  • 1
  • 9

1 Answers1

1

I see you have an AsyncTask to access your data from the server, but you don't really need an AsyncTask because performFiltering() already runs in the background, so you can put your doInBackground() logic in performFiltering().

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {

                ArrayList<String> resultList = null;
                FilterResults filterResults = new FilterResults();

                if (constraint != null) {
                    // Retrieve the autocomplete results.
                    Log.d(TAG, "Starting Search");

                    HttpURLConnection conn = null;
                    StringBuilder jsonResults = new StringBuilder();
                    try {
                        KEYWORD = constraint.toString();

                        ENDPOINT = Uri
                                .parse("https://maps.googleapis.com/maps/api/place/nearbysearch/json")
                                .buildUpon()
                                .appendQueryParameter("location", LOCATION)
                                .appendQueryParameter("radius", "10000")
                                .appendQueryParameter("keyword", KEYWORD)
                                .appendQueryParameter("key", API_KEY)
                                .build();

                        URL url = new URL(ENDPOINT.toString());

                        Log.d(TAG, "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);
                        }
                        Log.d(TAG, jsonResults.toString());
                    } catch (MalformedURLException e) {
                        Log.e(TAG, "Error processing Places API URL", e);
                        return filterResults ;
                    } catch (IOException e) {
                        Log.e(TAG, "Error connecting to Places API", e);
                        return filterResults ;
                    } 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("results");

                        // Extract the Place descriptions from the results
                        resultList = new ArrayList(predsJsonArray.length());
                        for (int i = 0; i < predsJsonArray.length(); i++) {
                            System.out.println(predsJsonArray.getJSONObject(i).getString("name"));
                            System.out.println(predsJsonArray.getJSONObject(i).getString("vicinity"));
                            System.out.println("=====================================================");
                            resultList.add(predsJsonArray.getJSONObject(i).getString("name"));
                            resultList.add(predsJsonArray.getJSONObject(i).getString("vicinity"));
                        }
                    } catch (JSONException e) {
                        Log.e(TAG, "Cannot process JSON results", e);
                    }
                    Log.d(TAG, resultList.toString());

                    // Assign the data to the FilterResults
                    filterResults.values = resultList;
                    filterResults.count = resultList.size();
                }
                return filterResults;
            }

A Filter works like an AsyncTask. performFiltering is like doInBackground and publishResults() is like onPostExecute().

Incidentally, don't update the adapter list in a background thread. Create a new list and assign it to FilterResults.values, then assign the adapter list in publishResults().

publishResults() should look like this:

            @Override
            protected void publishResults(CharSequence constraint, Filter.FilterResults results) {
                if (results != null && results.count > 0) {
                    resultList = (ArrayList) results.values;
                    notifyDataSetChanged();
                } else {
                    notifyDataSetInvalidated();
                }
            }
kris larson
  • 30,387
  • 5
  • 62
  • 74
  • I think this is working, but it still isn't giving me the drop down. It also crashes my app with the error "android.view.InflateException: Binary XML file line #7: Error inflating class fragment" and then " Caused by: java.lang.IllegalArgumentException: Binary XML file line #7: Duplicate id 0x7f0d0090, tag null, or parent id 0xffffffff with another fragment for com.google.android.gms.maps.SupportMapFragment". I think this error is in my XML, so I have added it to the problem. Got any ideas? – zahudson95 Dec 13 '15 at 03:38
  • 1
    So you have an error in one of your layout XML files. Post another question about that along with your layout XML. Once you get that straightened out, if you are still having problems with the autocomplete, post a comment here and we'll take another look. – kris larson Dec 13 '15 at 03:45
  • Oh, just saw your edit. I'm not sure, but I think it's complaining because the `RelativeLayout` that contains the map fragment doesn't have an ID. – kris larson Dec 13 '15 at 03:48
  • I asked the new question at this [link](http://stackoverflow.com/questions/34247932/autocompletetextview-over-mapsfragment) if you want to take a look. – zahudson95 Dec 13 '15 at 04:19