【问题标题】:Filter json results for Autocomplete adapter过滤自动完成适配器的 json 结果
【发布时间】:2015-12-13 01:35:40
【问题描述】:

我的应用程序有一个自动完成适配器,我正在从 Google Places API 获取 json 结果。我的麻烦是试图让结果显示在屏幕上。我正在使用本指南:http://examples.javacodegeeks.com/android/android-google-places-autocomplete-api-example/

在大多数情况下,代码看起来不错,但无论出于何种原因,我都无法将任何内容打印到我的显示器上。我不太了解过滤器的工作原理,也许解释一下它如何与自动完成适配器一起工作会有所帮助。

我的 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");



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


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

    }

我获取Json结果的方法是:

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

我的过滤器类是:

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

我知道我从 google 得到了一个合理的结果,我构建的数组看起来像这样(它包括名称和附近):

[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 社区合作社,2105 Lyndale Avenue South,明尼阿波利斯,陶自然 食品,2200 Hennepin Avenue,明尼阿波利斯,新鲜天然食品,1075 Highway 96 West, Saint Paul, Whole Foods Market, 222 Hennepin Avenue, 明尼阿波利斯, Sen Yai Sen Lek Thai, 2422 Central Avenue Northeast, 明尼阿波利斯,密西西比市场天然食品合作社,塞尔比大道 622 号, 圣保罗,东区食品合作社,2551 Central Avenue Northeast, 明尼阿波利斯,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, 明尼阿波利斯,彩虹食品,1566 University Avenue West,圣保罗, 蒲公英厨房卡车,800 Nicollet Mall,明尼阿波利斯,世界街 厨房,2743 Lyndale Avenue South #5,Minneapolis,CES Food Shelf, 明尼阿波利斯东 19 街]

感谢任何帮助,谢谢!

[编辑] 这是我的 activity_maps 的 XML:

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

【问题讨论】:

    标签: java android json google-places-api autocompletetextview


    【解决方案1】:

    我看到您有一个 AsyncTask 可以从服务器访问您的数据,但您实际上并不需要 AsyncTask,因为 performFiltering() 已经在后台运行,因此您可以将您的 doInBackground() 逻辑放入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;
                }
    

    Filter 的工作方式类似于 AsyncTaskperformFiltering 就像 doInBackgroundpublishResults() 就像 onPostExecute()

    顺便说一下,不要在后台线程中更新适配器列表。创建一个新列表并将其分配给FilterResults.values,然后将适配器列表分配给publishResults()

    publishResults() 应如下所示:

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

    【讨论】:

    • 我认为这是可行的,但它仍然没有给我下拉菜单。它还会使我的应用程序崩溃,并出现错误“android.view.InflateException: Binary XML file line #7: Error inflating class fragment”,然后是“ Caused by: java.lang.IllegalArgumentException: Binary XML file line #7: Duplicate id 0x7f0d0090,标记为 null,或父 id 为 0xffffffff,带有 com.google.android.gms.maps.SupportMapFragment 的另一个片段。我认为这个错误在我的 XML 中,所以我将它添加到问题中。有什么想法吗?
    • 所以您的一个布局 XML 文件中有错误。与您的布局 XML 一起发布另一个问题。理顺后,如果您仍然遇到自动完成问题,请在此处发表评论,我们会再看一下。
    • 哦,刚刚看到你的编辑。我不确定,但我认为这是在抱怨,因为包含地图片段的 RelativeLayout 没有 ID。
    • 如果你想看看,我在link 提出了新问题。
    猜你喜欢
    • 2011-08-27
    • 2014-05-09
    • 2013-09-14
    • 2014-09-16
    • 1970-01-01
    • 2013-05-13
    • 2013-07-25
    • 2012-01-24
    • 1970-01-01
    相关资源
    最近更新 更多