diff options
Diffstat (limited to 'docs/html/training/search/search.jd')
-rw-r--r-- | docs/html/training/search/search.jd | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/docs/html/training/search/search.jd b/docs/html/training/search/search.jd new file mode 100644 index 0000000..17e7640 --- /dev/null +++ b/docs/html/training/search/search.jd @@ -0,0 +1,217 @@ +page.title=Storing and Searching for Data +trainingnavtop=true +previous.title=Setting Up the Search Interface +previous.link=setup.html +next.title=Remaining Backward Compatible +next.link=backward-compat.html + +@jd:body + + <div id="tb-wrapper"> + <div id="tb"> + <h2>This lesson teaches you to</h2> + + <ul> + <li><a href="{@docRoot}training/search/search.html#create">Create the Virtual + Table</a></li> + + <li><a href="{@docRoot}training/search/search.html#populate">Populate the Virtual + Table</a></li> + + <li><a href="{@docRoot}training/search/search.html#search">Search for the Query</a></li> + </ul> + </div> + </div> + + <p>There are many ways to store your data, such as in an online database, in a local SQLite + database, or even in a text file. It is up to you to decide what is the best solution for your + application. This lesson shows you how to create a SQLite virtual table that can provide robust + full-text searching. The table is populated with data from a text file that contains a word and + definition pair on each line in the file.</p> + + <h2 id="create">Create the Virtual Table</h2> + + <p>A virtual table behaves similarly to a SQLite table, but reads and writes to an object in + memory via callbacks, instead of to a database file. To create a virtual table, create a class + for the table:</p> + <pre> +public class DatabaseTable { + private final DatabaseOpenHelper mDatabaseOpenHelper; + + public DatabaseTable(Context context) { + mDatabaseOpenHelper = new DatabaseOpenHelper(context); + } +} +</pre> + + <p>Create an inner class in <code>DatabaseTable</code> that extends {@link + android.database.sqlite.SQLiteOpenHelper}. The {@link android.database.sqlite.SQLiteOpenHelper} class + defines abstract methods that you must override so that your database table can be created and + upgraded when necessary. For example, here is some code that declares a database table that will + contain words for a dictionary app:</p> + <pre> +public class DatabaseTable { + + private static final String TAG = "DictionaryDatabase"; + + //The columns we'll include in the dictionary table + public static final String COL_WORD = "WORD"; + public static final String COL_DEFINITION = "DEFINITION"; + + private static final String DATABASE_NAME = "DICTIONARY"; + private static final String FTS_VIRTUAL_TABLE = "FTS"; + private static final int DATABASE_VERSION = 1; + + private final DatabaseOpenHelper mDatabaseOpenHelper; + + public DatabaseTable(Context context) { + mDatabaseOpenHelper = new DatabaseOpenHelper(context); + } + + private static class DatabaseOpenHelper extends SQLiteOpenHelper { + + private final Context mHelperContext; + private SQLiteDatabase mDatabase; + + private static final String FTS_TABLE_CREATE = + "CREATE VIRTUAL TABLE " + FTS_VIRTUAL_TABLE + + " USING fts3 (" + + COL_WORD + ", " + + COL_DEFINITION + ")"; + + DatabaseOpenHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + mHelperContext = context; + } + + @Override + public void onCreate(SQLiteDatabase db) { + mDatabase = db; + mDatabase.execSQL(FTS_TABLE_CREATE); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + + newVersion + ", which will destroy all old data"); + db.execSQL("DROP TABLE IF EXISTS " + FTS_VIRTUAL_TABLE); + onCreate(db); + } + } +} +</pre> + + <h2 id="populate">Populate the Virtual Table</h2> + + <p>The table now needs data to store. The following code shows you how to read a text file + (located in <code>res/raw/definitions.txt</code>) that contains words and their definitions, how + to parse that file, and how to insert each line of that file as a row in the virtual table. This + is all done in another thread to prevent the UI from locking. Add the following code to your + <code>DatabaseOpenHelper</code> inner class.</p> + + <p class="note"><strong>Tip:</strong> You also might want to set up a callback to notify your UI + activity of this thread's completion.</p> + <pre> +private void loadDictionary() { + new Thread(new Runnable() { + public void run() { + try { + loadWords(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + }).start(); + } + +private void loadWords() throws IOException { + final Resources resources = mHelperContext.getResources(); + InputStream inputStream = resources.openRawResource(R.raw.definitions); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + + try { + String line; + while ((line = reader.readLine()) != null) { + String[] strings = TextUtils.split(line, "-"); + if (strings.length < 2) continue; + long id = addWord(strings[0].trim(), strings[1].trim()); + if (id < 0) { + Log.e(TAG, "unable to add word: " + strings[0].trim()); + } + } + } finally { + reader.close(); + } +} + +public long addWord(String word, String definition) { + ContentValues initialValues = new ContentValues(); + initialValues.put(COL_WORD, word); + initialValues.put(COL_DEFINITION, definition); + + return mDatabase.insert(FTS_VIRTUAL_TABLE, null, initialValues); +} +</pre> + + <p>Call the <code>loadDictionary()</code> method wherever appropriate to populate the table. A + good place would be in the {@link android.database.sqlite.SQLiteOpenHelper#onCreate onCreate()} + method of the <code>DatabaseOpenHelper</code> class, right after you create the table:</p> + <pre> +@Override +public void onCreate(SQLiteDatabase db) { + mDatabase = db; + mDatabase.execSQL(FTS_TABLE_CREATE); + loadDictionary(); +} +</pre> + + <h2 id="search">Search for the Query</h2> + + <p>When you have the virtual table created and populated, use the query supplied by your {@link + android.widget.SearchView} to search the data. Add the following methods to the + <code>DatabaseTable</code> class to build a SQL statement that searches for the query:</p> + <pre> +public Cursor getWordMatches(String query, String[] columns) { + String selection = COL_WORD + " MATCH ?"; + String[] selectionArgs = new String[] {query+"*"}; + + return query(selection, selectionArgs, columns); +} + +private Cursor query(String selection, String[] selectionArgs, String[] columns) { + SQLiteQueryBuilder builder = new SQLiteQueryBuilder(); + builder.setTables(FTS_VIRTUAL_TABLE); + + Cursor cursor = builder.query(mDatabaseOpenHelper.getReadableDatabase(), + columns, selection, selectionArgs, null, null, null); + + if (cursor == null) { + return null; + } else if (!cursor.moveToFirst()) { + cursor.close(); + return null; + } + return cursor; +} +</pre> + + <p>Search for a query by calling <code>getWordMatches()</code>. Any matching results are returned + in a {@link android.database.Cursor} that you can iterate through or use to build a {@link android.widget.ListView}. + This example calls <code>getWordMatches()</code> in the <code>handleIntent()</code> method of the searchable + activity. Remember that the searchable activity receives the query inside of the {@link + android.content.Intent#ACTION_SEARCH} intent as an extra, because of the intent filter that you + previously created:</p> + <pre> +DatabaseTable db = new DatabaseTable(this); + +... + +private void handleIntent(Intent intent) { + + if (Intent.ACTION_SEARCH.equals(intent.getAction())) { + String query = intent.getStringExtra(SearchManager.QUERY); + Cursor c = db.getWordMatches(query, null); + //process Cursor and display results + } +} +</pre>
\ No newline at end of file |