【问题标题】:How to implement custom SearchView with voice search feature in Android?如何在 Android 中使用语音搜索功能实现自定义 SearchView?
【发布时间】:2016-11-24 17:08:31
【问题描述】:

我已经使用带有图标和编辑文本的线性布局创建了自定义搜索视图,因此当用户点击 EditText 时,我会处理这种情况。但是当用户关注 EditText 时,我还需要实现语音搜索。我看到了有关 SearchView 的示例,但所有这些示例都是关于内置工具栏 SearchView(使用菜单项)的。 是否可以在不使用标准 Android SearchView 的情况下实现语音搜索?

【问题讨论】:

    标签: android toolbar searchview


    【解决方案1】:

    当我尝试使用不带工具栏的 SearchView 时,我无法显示麦克风。我找不到任何关于如何在没有工具栏/操作栏的情况下使用 SearchView 的信息。我最终在工具栏上添加了一个额外的麦克风 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);
        }
    }
    

    【讨论】:

      【解决方案2】:

      此代码可以帮助您创建带有语音搜索的自定义搜索视图,在清单文件中添加可搜索的元数据并添加 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
      
          }
      }
      

      【讨论】:

      • 或者,有人知道如何在android中处理麦克风点击吗?
      猜你喜欢
      • 2018-06-08
      • 1970-01-01
      • 2013-07-24
      • 2017-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-16
      • 2018-06-21
      相关资源
      最近更新 更多