Search code examples
javaandroidxmlandroid-arrayadapterlayout-inflater

AutoCompleteTextView over MapsFragment


Screenshot of app

In my app I have a RelativeLayout->fragment(SupportMapFragment)|Relativelayout->AutoCompleteTextView

The search should do what Google Maps' search bar should do and return a dropdown list of locations from my search keyword. After I finish typing and a few second delay, my app crashes with the error:

12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime: FATAL EXCEPTION: main
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime: Process: com.hudsoncorp.zahudson.roadtrip, PID: 25010
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime: android.content.res.Resources$NotFoundException: Resource ID #0x7f0d0091 type #0x12 is not valid
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.content.res.Resources.loadXmlResourceParser(Resources.java:4165)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.content.res.Resources.getLayout(Resources.java:2268)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.view.LayoutInflater.inflate(LayoutInflater.java:413)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.java:371)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.widget.ArrayAdapter.getView(ArrayAdapter.java:362)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.widget.AbsListView.obtainView(AbsListView.java:2833)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.widget.ListPopupWindow$DropDownListView.obtainView(ListPopupWindow.java:1852)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.widget.ListView.measureHeightOfChildren(ListView.java:1292)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.widget.ListPopupWindow.buildDropDown(ListPopupWindow.java:1323)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.widget.ListPopupWindow.show(ListPopupWindow.java:709)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.widget.AutoCompleteTextView.showDropDown(AutoCompleteTextView.java:1128)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.widget.AutoCompleteTextView.updateDropDownForFilter(AutoCompleteTextView.java:996)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.widget.AutoCompleteTextView.onFilterComplete(AutoCompleteTextView.java:978)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.widget.Filter$ResultsHandler.handleMessage(Filter.java:285)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.os.Handler.dispatchMessage(Handler.java:102)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.os.Looper.loop(Looper.java:145)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at android.app.ActivityThread.main(ActivityThread.java:6938)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Native Method)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Method.java:372)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
12-12 21:59:13.138 25010-25010/com.hudsoncorp.zahudson.roadtrip E/AndroidRuntime:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)

I understand that this may be because I am not able to inflate a view over a fragment(https://stackoverflow.com/a/19815266/5336014). Is this something that is fixable?

XML code:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:id="@+id/activity_maps_layout"
                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:id="@+id/list_results"
            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>

OnCreate:

@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");

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

        autoCompView.setAdapter(new GooglePlacesAutocompleteAdapter(this, R.id.autoCompleteTextView));
        autoCompView.setOnItemClickListener(this);

    }

Adapter:

class GooglePlacesAutocompleteAdapter extends ArrayAdapter implements Filterable {
        private ArrayList resultList;

        private static final String TAG = "Filter";


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

        @Override
        public int getCount() {
            Log.d(TAG, resultList.toString());
            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) {

                    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;
                }

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

Also, I got this error solving another problem which can be found at this link: Filter json results for Autocomplete adapter

Thanks in advance.


Solution

  • The two argument constructor of ArrayAdapter i.e ArrayAdapter (Context context, int resource) expects layout resource and not id of a TextView.

    You are passing id of your AutoCompleteTextView that it tries to inflate but fails as there is no layout with that id. Change the line where you instantiate your adapter to:

    autoCompView.setAdapter(
                  new GooglePlacesAutocompleteAdapter(this,
                  android.R.layout.simple_list_item_1));