Using Android Search Dialog. Part 2 - Recent Query Suggestions

    image

    The article is recommended for reading to those who mastered the first part . The article explains how to modify your application so that tips for recent searches are added to the dialog. To understand the code and theory (in addition to the one required in the first part), knowledge of content providers is required. You can get it from the official guide .



    Bit of theory


    Essentially, recent search query hints are just saved searches. When the user selects one of the hints, the Activity that is responsible for the search receives an Intent of type Search with a hint as a string that it has already processed earlier. Search Manager is responsible for displaying prompts, as well as for the entire dialogue, and a content provider is used for storage.

    When the Search Manager defines our Activity as responsible for the search and providing hints for the search, the following sequence of actions occurs:
    1. When Search Manager receives the text of the search query, it sends its request to the content provider that provides the hints.
    2. The content provider returns a cursor pointing to hints that match the text of the search query.
    3. Search Manager displays tooltips using the cursor

    After the list of prompts has been displayed, the following may happen:
    • If the user changes the text of the request, then all of the above steps will be repeated.
    • If the user starts a search, the prompts are ignored.
    • If the user selects a tooltip, an Intent is delivered to Activity with the text of this tooltip as a request.

    So, to implement the hints, we need the following:
    • Create a content provider that will inherit from the SearchRecentSuggestionsProvider class and declare it in the manifest
    • Change the xml configuration file of the dialog by adding information about the content provider
    • Modify Activty so that it saves queries every time a search starts

    Create a content provider


    All that is required of us is a content provider, which is the descendant of the SearchRecentSuggestionsProvider class . This class practically does all the actions for the developer and all that is required of us is to write a constructor.

    File SuggestionProvider.java
    package com.example.search;

    import android.content.SearchRecentSuggestionsProvider;

    public class SuggestionProvider extends SearchRecentSuggestionsProvider {
      public final static String AUTHORITY = "com.example.search.SuggestionProvider";
      public final static int MODE = DATABASE_MODE_QUERIES;

      public SuggestionProvider() {
        setupSuggestions(AUTHORITY, MODE);
      }
    }

    * This source code was highlighted with Source Code Highlighter.

    The authorization string and the mode of operation of the content provider database are passed to the setupSuggestions () method . The authorization string can be any, the only requirement is uniqueness. However, in the official documentation, it is recommended to use the full name of the content provider, including the name of the package. The database operation mode should include DATABASE_MODE_QUERIES , also optionally you can add DATABASE_MODE_2LINES . In the second case, a column is added to the table of prompts, which allows displaying a second row for each prompt. The code will look like this:
    public final static int MODE = DATABASE_MODE_QUERIES | DATABASE_MODE_2LINES;

    * This source code was highlighted with Source Code Highlighter.

    Now do not forget that you need to declare our content provider in the manifest.

    AndroidManifest.xml File

       package="com.example.search"
       android:versionCode="1"
       android:versionName="1.0">
      
                  android:label="@string/app_name">
          
            
            
          

          
            
          

                   android:name="android.app.searchable"
            android:resource="@xml/searchable"
          />
        

                  android:authorities="com.example.search.SuggestionProvider" />    
      

      



    * This source code was highlighted with Source Code Highlighter.


    Change configuration file



    In order for the dialogue to use our content provider for tips, you need to add the parameters android: searchSuggestAuthority and android: searchSuggestSelection

    file searchable.xml

      android:label="@string/app_name"
      android:hint="@string/search_hint"
      android:searchSuggestAuthority="com.example.search.SuggestionProvider"
      android:searchSuggestSelection=" ?">


    * This source code was highlighted with Source Code Highlighter.

    The value of the android: searchSuggestAuthority parameter must fully match the authorization string of the content provider.
    The value of the android: searchSuggestSelection parameter should be a question mark placed after a space, because this is an argument to select from the database and the question mark is automatically replaced by the text entered by the user.

    Activity Change



    All we need to do is save the query text, for this an instance of the SearchRecentSuggestions class is created and the saveRecentQuery () method is called . This happens every time an Intent comes in to the Activity with a request to search for data. Two parameters are passed to the saveRecentQuery () method , the first is required and represents the search query string, the second is optional, it is required if you use DATABASE_MODE_2LINES to display the second line of text in the tooltip.

    The official documentation also recommends providing an interface for clearing the entire hint table. Apparently, this is necessary to ensure user's privacy. We will simply add another menu item, when clicked, the entire query history will be cleared.

    Main.java file
    package com.example.search;

    import android.app.ListActivity;
    import android.app.SearchManager;
    import android.content.Intent;
    import android.database.Cursor;
    import android.os.Bundle;
    import android.provider.SearchRecentSuggestions;
    import android.view.Menu;
    import android.view.MenuInflater;
    import android.view.MenuItem;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.SimpleCursorAdapter;

    public class Main extends ListActivity {
      private EditText text;
      private Button add;
      private RecordsDbHelper mDbHelper;

      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //Создаем экземпляр БД
        mDbHelper = new RecordsDbHelper(this);
        //Открываем БД для записи
        mDbHelper.open();
        //Получаем Intent
        Intent intent = getIntent();
        //Проверяем тип Intent
        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
          //Берем строку запроса из экстры
          String query = intent.getStringExtra(SearchManager.QUERY);
          //Создаем экземпляр SearchRecentSuggestions
          SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
              SuggestionProvider.AUTHORITY, SuggestionProvider.MODE);
          //Сохраняем запрос
          suggestions.saveRecentQuery(query, null);      
          //Выполняем поиск
          showResults(query);
        }

        add = (Button) findViewById(R.id.add);
        text = (EditText) findViewById(R.id.text);
        add.setOnClickListener(new View.OnClickListener() {
          public void onClick(View view) {
            String data = text.getText().toString();
            if (!data.equals("")) {
              saveTask(data);
              text.setText("");
            }
          }
        });
      }

      private void saveTask(String data) {
        mDbHelper.createRecord(data);
      }

      private void showResults(String query) {
        //Ищем совпадения
        Cursor cursor = mDbHelper.fetchRecordsByQuery(query);
        startManagingCursor(cursor);
        String[] from = new String[] { RecordsDbHelper.KEY_DATA };
        int[] to = new int[] { R.id.text1 };

        SimpleCursorAdapter records = new SimpleCursorAdapter(this,
            R.layout.record, cursor, from, to);
        //Обновляем адаптер
        setListAdapter(records);
      }
      //Создаем меню для вызова поиска (интерфейс в res/menu/main_menu.xml)
      public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main_menu, menu);
        return true;  
      }

      public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.search_record:
          //Вызываем поиск
          onSearchRequested();
          return true;
        case R.id.clear_recent_suggestions:
          //Очищаем историю
          SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
              SuggestionProvider.AUTHORITY, SuggestionProvider.MODE);
          suggestions.clearHistory();
          return true;
        default:
          return super.onOptionsItemSelected(item);
        }
      }
    }

    * This source code was highlighted with Source Code Highlighter.


    Conclusion

    When writing an article, we used documentation from developer.android.com.
    The entire modified project lies on code.google.com

    Also popular now: