我已经使用带有图标的线性布局创建了自定义搜索视图并编辑文本,因此当用户在deDittext上敲击用户时,我会处理这种情况。但是,当用户专注于EditText时,我也需要实现语音搜索。我看到了有关搜索视图的示例,但是所有这些示例都是关于内置工具栏搜索视图(使用菜单项)。是否可以在不使用标准Android搜索视图的情况下实现语音搜索?
尝试使用没有工具栏的搜索视图时,我无法显示麦克风。如果没有工具栏/操作栏,我找不到有关如何使用搜索视图的任何内容。我最终在工具栏上添加了一个额外的麦克风imageButton。这是一些示例代码来处理麦克风:
public class Main5Activity extends AppCompatActivity {
private static final int REQUEST_CODE = 1234;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main5);
ImageButton speakButton = findViewById(R.id.ib_speak);
// Disable button if no recognition service is present
PackageManager pm = getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(
new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
if (activities.size() == 0)
{
speakButton.setEnabled(false);
Toast.makeText(getApplicationContext(), "Recognizer not present", Toast.LENGTH_SHORT).show();
}
}
public void speakButtonClicked(View v)
{
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Voice recognition Demo...");
startActivityForResult(intent, REQUEST_CODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
// Populate the wordsList with the String values the recognition engine thought it heard
ArrayList<String> matches = data.getStringArrayListExtra(
RecognizerIntent.EXTRA_RESULTS);
if (matches != null) {
if (matches.size() > 0) {
mSearchView.setQuery(matches.get(0), false);
}
}
}
super.onActivityResult(requestCode, resultCode, data);
}
}
此代码可以帮助您使用语音搜索创建自定义搜索视图,在清单文件中添加可搜索的元数据,并添加search.xml。
searchActivity.java
import android.app.SearchManager;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.SearchRecentSuggestions;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
public class SearchableActivity extends FragmentActivity implements LoaderCallbacks<Cursor> {
ListView mLVCountries;
SimpleCursorAdapter mCursorAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_searchable);
// Getting reference to Country List
mLVCountries = (ListView)findViewById(R.id.lv_countries);
// Setting item click listener
mLVCountries.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent countryIntent = new Intent(getApplicationContext(), CountryActivity.class);
// Creating a uri to fetch country details corresponding to selected listview item
Uri data = Uri.withAppendedPath(CountryContentProvider.CONTENT_URI, String.valueOf(id));
// Setting uri to the data on the intent
countryIntent.setData(data);
// Open the activity
startActivity(countryIntent);
}
});
// Defining CursorAdapter for the ListView
mCursorAdapter = new SimpleCursorAdapter(getBaseContext(),
android.R.layout.simple_list_item_1,
null,
new String[] { SearchManager.SUGGEST_COLUMN_TEXT_1},
new int[] { android.R.id.text1}, 0);
// Setting the cursor adapter for the country listview
mLVCountries.setAdapter(mCursorAdapter);
// Getting the intent that invoked this activity
Intent intent = getIntent();
// If this activity is invoked by selecting an item from Suggestion of Search dialog or
// from listview of SearchActivity
if(intent.getAction().equals(Intent.ACTION_VIEW)){
Intent countryIntent = new Intent(this, CountryActivity.class);
countryIntent.setData(intent.getData());
startActivity(countryIntent);
finish();
}else if(intent.getAction().equals(Intent.ACTION_SEARCH)){ // If this activity is invoked, when user presses "Go" in the Keyboard of Search Dialog
String query = intent.getStringExtra(SearchManager.QUERY);
doSearch(query);
}
}
private void doSearch(String query){
Bundle data = new Bundle();
data.putString("query", query);
// Invoking onCreateLoader() in non-ui thread
getSupportLoaderManager().initLoader(1, data, this);
}
/** This method is invoked by initLoader() */
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle data) {
Uri uri = CountryContentProvider.CONTENT_URI;
return new CursorLoader(getBaseContext(), uri, null, null , new String[]{data.getString("query")}, null);
}
/** This method is executed in ui thread, after onCreateLoader() */
@Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor c) {
mCursorAdapter.swapCursor(c);
}
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
// TODO Auto-generated method stub
}
}
countrydb.java
import java.util.HashMap;
import android.app.SearchManager;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
public class CountryDB{
private static final String DBNAME = "country";
private static final int VERSION = 1;
private CountryDBOpenHelper mCountryDBOpenHelper;
private static final String FIELD_ID = "_id";
private static final String FIELD_NAME = "name";
private static final String FIELD_FLAG = "flag";
private static final String FIELD_CURRENCY = "currency";
private static final String TABLE_NAME = "countries";
private HashMap<String, String> mAliasMap;
public CountryDB(Context context){
mCountryDBOpenHelper = new CountryDBOpenHelper(context, DBNAME, null, VERSION);
// This HashMap is used to map table fields to Custom Suggestion fields
mAliasMap = new HashMap<String, String>();
// Unique id for the each Suggestions ( Mandatory )
mAliasMap.put("_ID", FIELD_ID + " as " + "_id" );
// Text for Suggestions ( Mandatory )
mAliasMap.put(SearchManager.SUGGEST_COLUMN_TEXT_1, FIELD_NAME + " as " + SearchManager.SUGGEST_COLUMN_TEXT_1);
// Icon for Suggestions ( Optional )
mAliasMap.put( SearchManager.SUGGEST_COLUMN_ICON_1, FIELD_FLAG + " as " + SearchManager.SUGGEST_COLUMN_ICON_1);
// This value will be appended to the Intent data on selecting an item from Search result or Suggestions ( Optional )
mAliasMap.put( SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, FIELD_ID + " as " + SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID );
}
/** Returns Countries */
public Cursor getCountries(String[] selectionArgs){
String selection = FIELD_NAME + " like ? ";
if(selectionArgs!=null){
selectionArgs[0] = "%"+selectionArgs[0] + "%";
}
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setProjectionMap(mAliasMap);
queryBuilder.setTables(TABLE_NAME);
Cursor c = queryBuilder.query(mCountryDBOpenHelper.getReadableDatabase(),
new String[] { "_ID",
SearchManager.SUGGEST_COLUMN_TEXT_1 ,
SearchManager.SUGGEST_COLUMN_ICON_1 ,
SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID } ,
selection,
selectionArgs,
null,
null,
FIELD_NAME + " asc ","10"
);
return c;
}
/** Return Country corresponding to the id */
public Cursor getCountry(String id){
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables(TABLE_NAME);
Cursor c = queryBuilder.query(mCountryDBOpenHelper.getReadableDatabase(),
new String[] { "_id", "name", "flag", "currency" } ,
"_id = ?", new String[] { id } , null, null, null ,"1"
);
return c;
}
class CountryDBOpenHelper extends SQLiteOpenHelper{
public CountryDBOpenHelper( Context context,
String name,
CursorFactory factory,
int version ) {
super(context, DBNAME, factory, VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String sql = "";
// Defining table structure
sql = " create table " + TABLE_NAME + "" +
" ( " +
FIELD_ID + " integer primary key autoincrement, " +
FIELD_NAME + " varchar(100), " +
FIELD_FLAG + " int, " +
FIELD_CURRENCY + " varchar(100) " +
" ) " ;
// Creating table
db.execSQL(sql);
for(int i=0;i<Country.countries.length;i++){
// Defining insert statement
sql = "insert into " + TABLE_NAME + " ( " +
FIELD_NAME + " , " +
FIELD_FLAG + " , " +
FIELD_CURRENCY + " ) " +
" values ( " +
" '" + Country.countries[i] + "' ," +
" " + Country.flags[i] + " ," +
" '" + Country.currency[i] + "' ) ";
// Inserting values into table
db.execSQL(sql);
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
}
countryActivity.java
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.widget.ImageView;
import android.widget.TextView;
public class CountryActivity extends FragmentActivity implements LoaderCallbacks<Cursor>{
private Uri mUri;
private ImageView mIvFlag;
private TextView mTvName;
private TextView mTvCurrency;
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.activity_country);
Intent intent = getIntent();
mUri = intent.getData();
mIvFlag = (ImageView) findViewById(R.id.iv_flag);
mTvName = (TextView) findViewById(R.id.tv_name);
mTvCurrency = (TextView) findViewById(R.id.tv_currency);
// Invokes the method onCreateloader() in non-ui thread
getSupportLoaderManager().initLoader(0, null, this);
}
/** Invoked by initLoader() */
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
return new CursorLoader(getBaseContext(), mUri, null, null , null, null);
}
/** Invoked by onCreateLoader(), will be executed in ui-thread */
@Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) {
if(cursor.moveToFirst()){
mIvFlag.setImageResource(cursor.getInt(cursor.getColumnIndex(cursor.getColumnName(2))));
mTvName.setText("Country: "+cursor.getString(cursor.getColumnIndex(cursor.getColumnName(1))));
mTvCurrency.setText("Currency: "+cursor.getString(cursor.getColumnIndex(cursor.getColumnName(3))));
}
}
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
// TODO Auto-generated method stub
}
}