关于android:将AutoCompleteTextView改为ActionBar中的SearchView

Turn AutoCompleteTextView into a SearchView in ActionBar instead

我有一个 AutoCompleteTextView,它为用户提供来自 Google Places API 的自动完成搜索结果。完成后,我发现了 SearchView 以及如何将其放置在 ActionBar 中。我查看了 google 提供的 SearchView 示例,并将其作为起点添加到我的应用程序中(它列出了已安装的应用程序),但我不知道如何从这里开始。我想拥有与 AutoCompleteTextView 相同的功能,但改用 SearchView。
有什么建议吗?
下面提供了整个课程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
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 java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.app.SearchManager;
import android.app.SearchableInfo;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.TextView;
import android.widget.Toast;



/**
 *
 * @author
 *
 */
public class PlacesListSearchActivity extends Activity implements SearchView.OnQueryTextListener{

    private static final String TAG ="PlacesListActivity";

    private ResultReceiver mReceiver;

    private OnSharedPreferenceChangeListener sharedPreferencesListener;
    private SharedPreferences sharedPreferences;

    /** Called when the activity is first created. */
    public ArrayAdapter<String> adapter;
    public AutoCompleteTextView textView;

    private SearchView mSearchView;
    private TextView mStatusView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
        setContentView(R.layout.places_search);
        mStatusView = (TextView) findViewById(R.id.status_text);


        final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.item_list);
        textView = (AutoCompleteTextView)findViewById(R.id.autoCompleteTextView1);
        adapter.setNotifyOnChange(true);
        textView.setHint("type store name");
        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) {

        }

        });
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);

        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.searchview_in_menu, menu);
        MenuItem searchItem = menu.findItem(R.id.action_search);
        mSearchView = (SearchView) searchItem.getActionView();
        setupSearchView(searchItem);

        return true;
    }

    private void setupSearchView(MenuItem searchItem) {

        if (isAlwaysExpanded()) {
            mSearchView.setIconifiedByDefault(false);
        } else {
            searchItem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM
                    | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
        }

        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        if (searchManager != null) {
            List<SearchableInfo> searchables = searchManager.getSearchablesInGlobalSearch();

            // Try to use the"applications" global search provider
            SearchableInfo info = searchManager.getSearchableInfo(getComponentName());
            for (SearchableInfo inf : searchables) {
                if (inf.getSuggestAuthority() != null
                        && inf.getSuggestAuthority().startsWith("applications")) {
                    info = inf;
                }
            }
            mSearchView.setSearchableInfo(info);
        }

        mSearchView.setOnQueryTextListener(this);
    }

    public boolean onQueryTextChange(String newText) {
        mStatusView.setText("Query =" + newText);
        return false;
    }

    public boolean onQueryTextSubmit(String query) {
        mStatusView.setText("Query =" + query +" : submitted");
        return false;
    }

    public boolean onClose() {
        mStatusView.setText("Closed!");
        return false;
    }

    protected boolean isAlwaysExpanded() {
        return false;
    }

    class GetPlaces extends AsyncTask<String, Void, ArrayList<String>> {
        @Override
        // three dots is java for an array of strings
        protected ArrayList<String> doInBackground(String... args)
        {
            Log.d("PlacesListActivity","doInBackground");
            ArrayList<String> predictionsArr = new ArrayList<String>();
            try
            {
                URL googlePlaces = new URL(
                       "https://maps.googleapis.com/maps/api/place/autocomplete/json?input=" +
                        URLEncoder.encode(args[0],"UTF-8") +
//                     "&types=geocode&language=en&sensor=true&key=" + SEARCHES FOR GEO CODES
                       "&types=establishment&language=en&sensor=true&key=" +
                        getResources().getString(R.string.googleAPIKey));

                Log.d("PlacesListActivity", googlePlaces.toString());

                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("PlacesListActivity","GetPlaces : doInBackground", e);
            } catch (JSONException e)
            {
            Log.e("PlacesListActivity","GetPlaces : doInBackground", e);
            }

            return predictionsArr;
        }

        @Override
        protected void onPostExecute(ArrayList<String> result){
            Log.d("PlacesListActivity","onPostExecute :" + result.size());
            //update the adapter
            adapter = new ArrayAdapter<String>(getBaseContext(), R.layout.item_list);
            adapter.setNotifyOnChange(true);
            //attach the adapter to textview
            textView.setAdapter(adapter);

            for (String string : result) {
                Log.d("PlacesListActivity","onPostExecute : result =" + string);
                adapter.add(string);
                adapter.notifyDataSetChanged();
            }

            Log.d("PlacesListActivity","onPostExecute : autoCompleteAdapter" + adapter.getCount());
        }

    }

}

更新saxman建议的代码后,我可以看到provider中的查询方法从来没有被调用过:

我的清单文件如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.rathinavelu.rea"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-sdk
        android:minSdkVersion="7"
        android:targetSdkVersion="15" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name">

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait">
            <intent-filter>
               
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

       
        </activity>

       
           
            <meta-data
                android:name="android.app.searchable"
                android:resource="@xml/searchable" />
        </activity>

       
        </activity>

       
        </activity>

       
        </activity>

        <uses-library android:name="com.google.android.maps" />

        <service
            android:name=".places.PlacesRESTService"
            android:enabled="true"
            android:exported="false">
            <intent-filter>
               
            </intent-filter>
        </service>

        <provider
            android:name=".places.PlacesSuggestionProvider"
            android:authorities="com.rathinavelu.rea.places.search_suggestion_provider"
            android:syncable="false" />

    </application>

</manifest>

我在清单、内容提供者和清单文件中使用相同的权限。我在菜单中看到了 searchView 并且我没有修改查询方法,所以它应该只返回一行光标。但查询方法永远不会被调用。请帮忙。
我刚刚发现的另一个问题是 searchView 没有显示指定的 search_hint!

提供更多代码
*PlacesListSearchActivity.java*

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class PlacesListSearchActivity extends Activity {

        private static final String TAG ="PlacesListSearchActivity";

        private ResultReceiver mReceiver;

        private OnSharedPreferenceChangeListener sharedPreferencesListener;
        private SharedPreferences sharedPreferences;

    /** Called when the activity is first created. */
        public ArrayAdapter<String> adapter;
        public AutoCompleteTextView textView;

        private SearchView mSearchView;
        private TextView mStatusView;

        @Override
    public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
                setContentView(R.layout.places_search);
                mStatusView = (TextView) findViewById(R.id.status_text);


                final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.item_list);
                textView = (AutoCompleteTextView)findViewById(R.id.autoCompleteTextView1);
                adapter.setNotifyOnChange(true);
                textView.setHint("type store name");
                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) {

                }

                });
        }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
//        super.onCreateOptionsMenu(menu);
        // Inflate the options menu from XML
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.places_list_search_options_menu, menu);

        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
        // Tells your app's SearchView to use this activity's searchable configuration
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        searchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default

//        setupSearchView(searchItem);

        return true;
    }

places_search.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?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_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="10dp">
        <requestFocus></requestFocus>
        </AutoCompleteTextView>

    <TextView
            android:id="@+id/status_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"/>
</RelativeLayout>

places_list_search_options_menu.xml

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_search"
          android:title="@string/menu_search"
          android:icon="@android:drawable/ic_menu_search"
          android:showAsAction="collapseActionView|ifRoom"
          android:actionViewClass="android.widget.SearchView" />
</menu>

可搜索的.xml

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/app_name"
    android:hint="@string/search_hint"
    android:searchSuggestAuthority="com.rathinavelu.rea.places.search_suggestion_provider">
</searchable>

PlacesSuggestionProvider.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public class PlacesSuggestionProvider extends ContentProvider {
    private static final String LOG_TAG ="PlacesSuggestionProvider";

    public static final String AUTHORITY ="com.rathinavelu.rea.places.search_suggestion_provider";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY +"/search");

    // UriMatcher constant for search suggestions
    private static final int SEARCH_SUGGEST = 1;

    private static final UriMatcher uriMatcher;

    private static final String[] SEARCH_SUGGEST_COLUMNS = {
            BaseColumns._ID,
            SearchManager.SUGGEST_COLUMN_TEXT_1,
            SearchManager.SUGGEST_COLUMN_TEXT_2,
            SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID
    };

    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, SEARCH_SUGGEST);
        uriMatcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY +"/*", SEARCH_SUGGEST);
    }

    @Override
    public int delete(Uri uri, String arg1, String[] arg2) {
        throw new UnsupportedOperationException();
    }

    @Override
    public String getType(Uri uri) {
        switch (uriMatcher.match(uri)) {
            case SEARCH_SUGGEST:
                return SearchManager.SUGGEST_MIME_TYPE;
            default:
                throw new IllegalArgumentException("Unknown URL" + uri);
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues arg1) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean onCreate() {
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
            String sortOrder) {
        Log.d(LOG_TAG,"query =" + uri);

        // Use the UriMatcher to see what kind of query we have
        switch (uriMatcher.match(uri)) {
            case SEARCH_SUGGEST:
                Log.d(LOG_TAG,"Search suggestions requested.");
                MatrixCursor cursor = new MatrixCursor(SEARCH_SUGGEST_COLUMNS, 1);
                cursor.addRow(new String[] {
                       "1","Search Result","Search Result Description","content_id"
                });
                return cursor;
            default:
                throw new IllegalArgumentException("Unknown Uri:" + uri);
        }
    }

    @Override
    public int update(Uri uri, ContentValues arg1, String arg2, String[] arg3) {
        throw new UnsupportedOperationException();
    }
}


要在 SearchView 中获取 Places Autocomplete API 结果,您首先需要 API 的 ContentProvider。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.provider.BaseColumns;
import android.util.Log;

public class PlacesSuggestionProvider extends ContentProvider {
    private static final String LOG_TAG ="ExampleApp";

    public static final String AUTHORITY ="com.example.google.places.search_suggestion_provider";
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY +"/search");

    // UriMatcher constant for search suggestions
    private static final int SEARCH_SUGGEST = 1;

    private static final UriMatcher uriMatcher;

    private static final String[] SEARCH_SUGGEST_COLUMNS = {
            BaseColumns._ID,
            SearchManager.SUGGEST_COLUMN_TEXT_1,
            SearchManager.SUGGEST_COLUMN_TEXT_2,
            SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID
    };

    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, SEARCH_SUGGEST);
        uriMatcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY +"/*", SEARCH_SUGGEST);
    }

    @Override
    public int delete(Uri uri, String arg1, String[] arg2) {
        throw new UnsupportedOperationException();
    }

    @Override
    public String getType(Uri uri) {
        switch (uriMatcher.match(uri)) {
            case SEARCH_SUGGEST:
                return SearchManager.SUGGEST_MIME_TYPE;
            default:
                throw new IllegalArgumentException("Unknown URL" + uri);
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues arg1) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean onCreate() {
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
            String sortOrder) {
        Log.d(LOG_TAG,"query =" + uri);

        // Use the UriMatcher to see what kind of query we have
        switch (uriMatcher.match(uri)) {
            case SEARCH_SUGGEST:
                Log.d(LOG_TAG,"Search suggestions requested.");
                MatrixCursor cursor = new MatrixCursor(SEARCH_SUGGEST_COLUMNS, 1);
                cursor.addRow(new String[] {
                       "1","Search Result","Search Result Description","content_id"
                });
                return cursor;
            default:
                throw new IllegalArgumentException("Unknown Uri:" + uri);
        }
    }

    @Override
    public int update(Uri uri, ContentValues arg1, String arg2, String[] arg3) {
        throw new UnsupportedOperationException();
    }
}

然后将您的 Places Autocomplete API 客户端代码添加到内容提供程序的查询方法中。您提取用户输入如下:

1
String query = uri.getLastPathSegment().toLowerCase();

将 PlacesSuggestionProvider 添加到您的 AndroidManifest,并确保您的活动具有可搜索的配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name">

       
            <intent-filter>
               
               

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data
                android:name="android.app.searchable"
                android:resource="@xml/searchable" />
        </activity>

        <provider
            android:name="com.example.google.places.PlacesSuggestionProvider"
            android:authorities="com.example.google.places.search_suggestion_provider"
            android:syncable="false" />
    </application>

</manifest>

并确保您的可搜索配置 (res/xml/searchable.xml) 具有搜索建议权限。

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/app_name"
    android:hint="@string/search_hint"
    android:searchSuggestAuthority="com.example.google.places.search_suggestion_provider">
</searchable>

AndroidManifest.xml、searchable.xml 和你的内容提供者中的权限应该相同。

为包含 SearchView (/res/menu/options_menu.xml) 的 ActionBar 创建一个选项菜单。

1
2
3
4
5
6
7
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_search"
          android:title="@string/menu_search"
          android:icon="@drawable/ic_menu_search"
          android:showAsAction="collapseActionView|ifRoom"
          android:actionViewClass="android.widget.SearchView" />
</menu>

使用与您的可搜索配置相关联的 SearchView 配置您的 Activity/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the options menu from XML
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.options_menu, menu);

    SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
    // Tells your app's SearchView to use this activity's searchable configuration
    searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
    searchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default

    return true;
}

几个关键文档是:

添加自定义建议:
http://developer.android.com/guide/topics/search/adding-custom-suggestions.html

创建内容提供者:
http://developer.android.com/guide/topics/providers/content-provider-creating.html

使用搜索小部件:
http://developer.android.com/guide/topics/search/search-dialog.html#UsingSearchWidget


带有谷歌搜索 API 的 AutoCompleteTextView

enter

1
2
3
4
5
6
7
8
9
10
11
12
  <AutoCompleteTextView
    android:id="@+id/main_omnibox_input"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:background="@null"
    android:hint="Search"  
    android:focusable="true"
    android:focusableInTouchMode="true"                                  
    android:selectAllOnFocus="true"
    android:singleLine="true"
    android:textSize="@dimen/_14sdp" />

你的java代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  this.inputBox = (AutoCompleteTextView) findViewById(R.id.main_omnibox_input);
  inputBox.setAdapter(new SearchAutocompleteAdapter(SearchActivity.this, new SearchAutocompleteAdapter.OnSearchCommitListener() {
        @Override
        public void onSearchCommit(String text) {
            inputBox.setText(text);
            inputBox.setSelection(text.length());
        }
    }));


    this.inputBox.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView< ? > adapterView, View view, int i, long j) {
            String charSequence = ((TextView) view.findViewById(android.R.id.text1)).getText().toString();
            inputBox.setText(Html.fromHtml(BrowserUnit.urlWrapper(charSequence)), BufferType.SPANNABLE);
            inputBox.setSelection(charSequence.length());
           // your code
           // updateAlbum(charSequence);
           // hideSoftInput(SearchActivity.this.inputBox);
        }
    });

搜索自动完成适配器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
public class SearchAutocompleteAdapter extends BaseAdapter implements Filterable {

interface OnSearchCommitListener {
    void onSearchCommit(String text);
}

private final Context mContext;
private final OnSearchCommitListener commitListener;
private List<String> completions = new ArrayList<>();
static final String searchCompleteUrl ="https://www.google.com/complete/search?client=firefox&q=%s";

SearchAutocompleteAdapter(Context context, OnSearchCommitListener commitListener) {
    mContext = context;
    this.commitListener = commitListener;
}

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

@Override
public Object getItem(int position) {
    return completions.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@SuppressLint("ClickableViewAccessibility")
@Override
@SuppressWarnings("ConstantConditions")
public View getView(final int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(android.R.layout.simple_dropdown_item_1line, parent, false);
    }
    TextView textview = convertView.findViewById(android.R.id.text1);
    textview.setText(completions.get(position));
    Drawable d = ContextCompat.getDrawable(mContext, R.drawable.icon_goarrowsmall);
    final int size = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 32, mContext.getResources().getDisplayMetrics());
    d.setBounds(0, 0, size, size);
    textview.setCompoundDrawables(null, null, d, null);

    textview.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent event) {
            if (event.getAction() != MotionEvent.ACTION_DOWN) {
                return false;
            }
            TextView t = (TextView) view;
            if (event.getX() > t.getWidth() - t.getCompoundPaddingRight()) {
                commitListener.onSearchCommit(getItem(position).toString());
                return true;
            }
            return false;
        }
    });
    parent.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent event) {
            if (event.getX() > view.getWidth() - size * 2) {
                return true;
            }
            return false;
        }
    });
    return convertView;
}

@Override
public Filter getFilter() {
    return new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            // Invoked on a worker thread
            FilterResults filterResults = new FilterResults();
            if (constraint != null) {
                List<String> results = getCompletions(constraint.toString());
                filterResults.values = results;
                filterResults.count = results.size();
            }
            return filterResults;
        }

        @Override
        @SuppressWarnings("unchecked")
        protected void publishResults(CharSequence constraint, FilterResults results) {
            if (results != null && results.count > 0) {
                completions = (List<String>) results.values;
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }
    };
}

private List<String> getCompletions(String text) {
    int total = 0;
    byte[] data = new byte[16384];
    try {
        URL url = new URL(URLUtil.composeSearchUrl(text, searchCompleteUrl,"%s"));
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        try {
            InputStream in = new BufferedInputStream(urlConnection.getInputStream());
            while (total <= data.length) {
                int count = in.read(data, total, data.length - total);
                if (count == -1) {
                    break;
                }
                total += count;
            }
            if (total == data.length) {
                // overflow
                return new ArrayList<>();
            }
        } finally {
            urlConnection.disconnect();
        }
    } catch (IOException e) {
        return new ArrayList<>();
    }

    JSONArray jsonArray;
    try {
        jsonArray = new JSONArray(new String(data, StandardCharsets.UTF_8));
    } catch (JSONException e) {
        return new ArrayList<>();
    }
    jsonArray = jsonArray.optJSONArray(1);
    if (jsonArray == null) {
        return new ArrayList<>();
    }
    final int MAX_RESULTS = 10;
    List<String> result = new ArrayList<>(Math.min(jsonArray.length(), MAX_RESULTS));
    for (int i = 0; i < jsonArray.length() && result.size() < MAX_RESULTS; i++) {
        String s = jsonArray.optString(i);
        if (s != null && !s.isEmpty()) {
            result.add(s);
        }
    }
    return result;
}

}