(二)进阶练习____7、添加搜索功能——数据的存储和检索
原文链接:http://docs.eoeandroid.com/training/search/search.html 作者:zachgenius 完成时间:2012-8-31
目录[隐藏] |
保存与检索数据
有许多方法来存储你的数据,比如用在线数据库,本地SQLite数据库或者甚至是在一个文本文档中。 具体哪种方案最适合你的程序,这取决于你。本节课讲解如何创建一个能提供强大的全文搜索功能的SQLite虚拟表。该表被一个文本文档中的数据所填充,而该文档每一行中都包含一个单字-定义对。
创建虚拟表
一个虚拟表很像SQLite表,但却是从内存中读写一个对象,而非通过数据库文件。为了建立一个虚拟表,需要为这个表创建一个类:
public class DatabaseTable { private final DatabaseOpenHelper mDatabaseOpenHelper; public DatabaseTable(Context context) { mDatabaseOpenHelper = new DatabaseOpenHelper(context); } }
在DatabaseTable中创建一个内部类,并且该内部类须继承SQLiteOpenHelper。SQLiteOpenHelper类定义了一些抽象方法,而你必须重写他们以便让你的数据库表在需要的时候能够创建和升级。例如如下的代码,声明了一个存有字典应用所需单词的数据表:
public class DatabaseTable { private static final String TAG = "DictionaryDatabase"; //在字典表中包含的字段 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); } } }
填充虚拟表
现在这个表需要保存。以下的代码演示了如何读取一个包含了单词和它们的释义的文本文档(位置在res/raw/definitions.txt),如何解析该文件,以及如何将该文件中的每一行插入虚拟表的一行当中。这些工作将在别的线程中去执行,以防止UI被锁定。
小贴士:你也有可能想要设定一个回调函数当该线程完成时通知你的UI activity。
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); }
在任何需要填充表的地方都要调用loadDictionary()方法。比如DatabaseOpenHelper类的onCreate()方法中应该是个好地方,恰好在你创建完表之后:
@Overridepublic void onCreate(SQLiteDatabase db) { mDatabase = db; mDatabase.execSQL(FTS_TABLE_CREATE); loadDictionary(); }
检索查询
当你创建并填充万虚拟表之后,使用SearchView提供的查询方法来检索数据。在DatabaseTable中增加以下方法来建立一个SQL搜索语句:
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; }
通过调用getWordMatches()方法进行检索查询。任何符合条件的结果将被返回到一个Cursor游标当中,它可以用来遍历,或者用来建立一个ListView。在本例中在用于搜索的activity的handleIntent()中调用了getWordMatches()方法。请记住,这个用于搜索的activity由于你之前建立的intent filter的原因,要接受一个额外的ACTION_SEARCH intent中的检索:
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); //处理游标Cursor并且显示结果 } }

浙公网安备 33010602011771号