Tengo un AutoCompleteTextView, que da al usuario la finalización automática de resultados de búsqueda de Google Places API . Una vez que terminé descubrí SearchView y cómo se puede colocar en ActionBar. Revisé el ejemplo de SearchView provisto por google y lo agregué a mi aplicación como punto de partida (enumera las aplicaciones instaladas) pero no sé cómo proceder desde aquí. Quiero tener la misma funcionalidad que AutoCompleteTextView, pero en su lugar uso SearchView. ¿Alguna sugerencia? Toda la clase se proporciona a continuación.AutoCompleteTextView en un SearchView en la Barra de acciones en lugar
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());
}
}
}
Después de actualizar el código sugerido por saxman, puedo ver que el método de consulta en el proveedor nunca es llamado:
Mi archivo de manifiesto es el siguiente:
<?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>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".PlacesListActivity" >
</activity>
<activity android:name=".PlacesListSearchActivity" >
<action android:name="android.intent.action.SEARCH" />
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<activity android:name=".TestMapActivity" >
</activity>
<activity android:name=".SettingsPreferencesActivity" >
</activity>
<activity android:name="com.rathinavelu.util.ConnectionChecker" >
</activity>
<uses-library android:name="com.google.android.maps" />
<service
android:name=".places.PlacesRESTService"
android:enabled="true"
android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.ACTION_SYNC" />
</intent-filter>
</service>
<provider
android:name=".places.PlacesSuggestionProvider"
android:authorities="com.rathinavelu.rea.places.search_suggestion_provider"
android:syncable="false" />
</application>
</manifest>
I use la misma autoridad en el manifiesto, el proveedor de contenido y el archivo de manifiesto. Veo searchView en el menú y no he modificado el método de consulta, así que debería devolver el cursor de una línea. pero el método de consulta nunca se llama. por favor ayuda. ¡Otro problema que acabo de descubrir es que el searchView no muestra el search_hint especificado!
Proporcionar más código * PlacesListSearchActivity.java *
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
<?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
<?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>
searchable.xml
<?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
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();
}
}
Hola, pregunto, ¿hay alguna ventaja para el uso de SearchView sobre AutoCompleteTextView para la funcionalidad de búsqueda en la barra de acción? –
Excelente enlace para futuros servidores; http://www.drzon.net/how-to-create-a-clearable-autocomplete-dropdown-with-autocompletetextview/ – Tina