我在安卓中实现 DictionaryDatabase。当时我有一个 EditText 视图,我在其中输入一个单词,匹配的单词来自数据库。现在的问题是我的数据库太大了。就像单词“A”一样,我有 200 到 300 个单词。第一次安装应用程序时,必须加载数据库,这需要 1 到 3 分钟,这太可怕了。现在我希望在应用程序安装后或单击 EditTex 意味着焦点上我应该调用带有 ProgressDialogue 框的 asyntask。在数据库中执行 loadWords 并在完成时关闭对话。我知道异步任务,但我不知道如何为我的代码使用异步
这是数据库加载类的代码:
/**
* Contains logic to return specific words from the dictionary, and
* load the dictionary table when it needs to be created.
*/
public class DictionaryDatabase extends SQLiteOpenHelper {
private static final String TAG = "DictionaryDatabase";
final static String DB_DESTINATION = "/data/data/YOUR_PACKAGE_NAME/databases/dictionary.db";
private DictionaryDatabase mDictionary;
//****FOr Dictionary****//
static int [] raw_textFiles={R.raw.a,R.raw.b,R.raw.c,
R.raw.d,R.raw.e,R.raw.f,
R.raw.g,R.raw.h,R.raw.i,
R.raw.j,R.raw.k,R.raw.l,
R.raw.m,R.raw.n,R.raw.o,
R.raw.p,R.raw.q,R.raw.r,
R.raw.s,R.raw.t,R.raw.u,
R.raw.v,R.raw.w,R.raw.x,
R.raw.y,R.raw.z};
//Array for Parsing Use
ArrayList<String> Words = new ArrayList<String>();
private static String word;
private final Context mHelperContext;
private SQLiteDatabase mDatabase;
private ProgressDialog dialog;
//The columns we'll include in the dictionary table
public static final String KEY_WORD = SearchManager.SUGGEST_COLUMN_TEXT_1;
public static final String KEY_DEFINITION = SearchManager.SUGGEST_COLUMN_TEXT_2;
private static final String DATABASE_NAME = "dictionary";
private static final String FTS_VIRTUAL_TABLE = "FTSdictionary";
private static final int DATABASE_VERSION = 2;
private static final HashMap<String,String> mColumnMap = buildColumnMap();
private static final String FTS_TABLE_CREATE =
"CREATE VIRTUAL TABLE " + FTS_VIRTUAL_TABLE +
" USING fts3 (" +
KEY_WORD + ", " +
KEY_DEFINITION + ");";
/**
* Constructor
* @param context The Context within which to work, used to create the DB
*/
public DictionaryDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mHelperContext = context;
}
/**
* Builds a map for all columns that may be requested, which will be given to the
* SQLiteQueryBuilder. This is a good way to define aliases for column names, but must include
* all columns, even if the value is the key. This allows the ContentProvider to request
* columns w/o the need to know real column names and create the alias itself.
*/
private static HashMap<String,String> buildColumnMap() {
HashMap<String,String> map = new HashMap<String,String>();
map.put(KEY_WORD, KEY_WORD);
map.put(KEY_DEFINITION, KEY_DEFINITION);
map.put(BaseColumns._ID, "rowid AS " +
BaseColumns._ID);
map.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, "rowid AS " +
SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID);
map.put(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID, "rowid AS " +
SearchManager.SUGGEST_COLUMN_SHORTCUT_ID);
return map;
}
/**
* Returns a Cursor positioned at the word specified by rowId
*
* @param rowId id of word to retrieve
* @param columns The columns to include, if null then all are included
* @return Cursor positioned to matching word, or null if not found.
*/
public Cursor getWord(String rowId, String[] columns) {
String selection = "rowid = ?";
String[] selectionArgs = new String[] {rowId};
return query(selection, selectionArgs, columns);
/* This builds a query that looks like:
* SELECT <columns> FROM <table> WHERE rowid = <rowId>
*/
}
/**
* Returns a Cursor over all words that match the given query
*
* @param query The string to search for
* @param columns The columns to include, if null then all are included
* @return Cursor over all words that match, or null if none found.
*/
public Cursor getWordMatches(String query, String[] columns) {
String selection = KEY_WORD + " MATCH ?";
String[] selectionArgs = new String[] {query+"*"};
return query(selection, selectionArgs, columns);
/* This builds a query that looks like:
* SELECT <columns> FROM <table> WHERE <KEY_WORD> MATCH 'query*'
* which is an FTS3 search for the query text (plus a wildcard) inside the word column.
*
* - "rowid" is the unique id for all rows but we need this value for the "_id" column in
* order for the Adapters to work, so the columns need to make "_id" an alias for "rowid"
* - "rowid" also needs to be used by the SUGGEST_COLUMN_INTENT_DATA alias in order
* for suggestions to carry the proper intent data.
* These aliases are defined in the DictionaryProvider when queries are made.
* - This can be revised to also search the definition text with FTS3 by changing
* the selection clause to use FTS_VIRTUAL_TABLE instead of KEY_WORD (to search across
* the entire table, but sorting the relevance could be difficult.
*/
}
/**
* Performs a database query.
* @param selection The selection clause
* @param selectionArgs Selection arguments for "?" components in the selection
* @param columns The columns to return
* @return A Cursor over all rows matching the query
*/
private Cursor query(String selection, String[] selectionArgs, String[] columns) {
/* The SQLiteBuilder provides a map for all possible columns requested to
* actual columns in the database, creating a simple column alias mechanism
* by which the ContentProvider does not need to know the real column names
*/
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
builder.setTables(FTS_VIRTUAL_TABLE);
builder.setProjectionMap(mColumnMap);
Cursor cursor = builder.query(getReadableDatabase(),
columns, selection, selectionArgs, null, null, null);
if (cursor == null) {
return null;
} else if (!cursor.moveToFirst()) {
cursor.close();
return null;
}
return cursor;
}
/**
* This creates/opens the database.
*/
@Override
public void onCreate(SQLiteDatabase db) {
mDatabase = db;
Log.i("PATH",""+mDatabase.getPath());
mDatabase.execSQL(FTS_TABLE_CREATE);
// loadDictionary();
}
/**
* Starts a thread to load the database table with words
*/
private void loadDictionary() {
new Thread(new Runnable() {
public void run() {
try {
loadWords();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
}
public void loadWords() throws IOException {
Log.d(TAG, "Loading words...");
for(int i=0;i<=25;i++)
{ //***//
final Resources resources = mHelperContext.getResources();
InputStream inputStream = resources.openRawResource(raw_textFiles[i]);
//InputStream inputStream = resources.openRawResource(R.raw.definitions);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
StringBuilder sb = new StringBuilder();
while ((word = reader.readLine()) != null)
{
sb.append(word);
// Log.i("WORD in Parser", ""+word);
}
String contents = sb.toString();
StringTokenizer st = new StringTokenizer(contents, "||");
while (st.hasMoreElements()) {
String row = st.nextElement().toString();
String title = row.substring(0, row.indexOf("$$$"));
String desc = row.substring(row.indexOf("$$$") + 3);
// Log.i("Strings in Database",""+title+""+desc);
long id = addWord(title,desc);
if (id < 0) {
Log.e(TAG, "unable to add word: " + title);
}
}
} finally {
reader.close();
}
} //***//
Log.d(TAG, "DONE loading words.");
}
/**
* Add a word to the dictionary.
* @return rowId or -1 if failed
*/
public long addWord(String word, String definition) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_WORD, word);
initialValues.put(KEY_DEFINITION, definition);
return mDatabase.insert(FTS_VIRTUAL_TABLE, null, initialValues);
}
@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);
}
}
更新: EditTEx 搜索;
//::::::::::::::::::::::TextWatcher For EditTextView :::::::::::::::::::::://
TextWatcher myTextWatcher = new TextWatcher() {
@SuppressLint("NewApi")
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
query= (search.getText().toString());
char character = 0;
if(query.isEmpty()==false)
{
character=query.toLowerCase().charAt(0);
}
if (start==0) {
//Log.i("query",""+query);
Cursor cursor = managedQuery(DictionaryProvider.CONTENT_URI, null, null,new String[] {query}, null);
viewFlipper.showNext();
}
listAdapter.notifyDataSetChanged();
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@SuppressLint("NewApi")
@Override
public void afterTextChanged(Editable s) {
query= s.toString();
char character = 0;
if(query.isEmpty()==false)
{
character=query.toLowerCase().charAt(0);
}
Cursor cursor = managedQuery(DictionaryProvider.CONTENT_URI, null, null,new String[] {query}, null);
listAdapter.getFilter().filter(s);
}
};
这是提供者类:
*/
private static UriMatcher buildUriMatcher() {
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
// to get definitions...
matcher.addURI(AUTHORITY, "dictionary", SEARCH_WORDS);
matcher.addURI(AUTHORITY, "dictionary/#", GET_WORD);
// to get suggestions...
matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, SEARCH_SUGGEST);
matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", SEARCH_SUGGEST);
/* The following are unused in this implementation, but if we include
* {@link SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} as a column in our suggestions table, we
* could expect to receive refresh queries when a shortcutted suggestion is displayed in
* Quick Search Box, in which case, the following Uris would be provided and we
* would return a cursor with a single item representing the refreshed suggestion data.
*/
matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT, REFRESH_SHORTCUT);
matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", REFRESH_SHORTCUT);
return matcher;
}
@Override
public boolean onCreate() {
mDictionary = new DictionaryDatabase(getContext());
return true;
}
/**
* Handles all the dictionary searches and suggestion queries from the Search Manager.
* When requesting a specific word, the uri alone is required.
* When searching all of the dictionary for matches, the selectionArgs argument must carry
* the search query as the first element.
* All other arguments are ignored.
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
// Use the UriMatcher to see what kind of query we have and format the db query accordingly
switch (sURIMatcher.match(uri)) {
case SEARCH_SUGGEST:
if (selectionArgs == null) {
throw new IllegalArgumentException(
"selectionArgs must be provided for the Uri: " + uri);
}
return getSuggestions(selectionArgs[0]);
case SEARCH_WORDS:
if (selectionArgs == null) {
throw new IllegalArgumentException(
"selectionArgs must be provided for the Uri: " + uri);
}
return search(selectionArgs[0]);
case GET_WORD:
return getWord(uri);
case REFRESH_SHORTCUT:
return refreshShortcut(uri);
default:
throw new IllegalArgumentException("Unknown Uri: " + uri);
}
}
private Cursor getSuggestions(String query) {
query = query.toLowerCase();
String[] columns = new String[] {
BaseColumns._ID,
DictionaryDatabase.KEY_WORD,
DictionaryDatabase.KEY_DEFINITION,
/* SearchManager.SUGGEST_COLUMN_SHORTCUT_ID,
(only if you want to refresh shortcuts) */
SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID};
return mDictionary.getWordMatches(query, columns);
}
private Cursor search(String query) {
query = query.toLowerCase();
String[] columns = new String[] {
BaseColumns._ID,
DictionaryDatabase.KEY_WORD,
DictionaryDatabase.KEY_DEFINITION};
return mDictionary.getWordMatches(query, columns);
}
private Cursor getWord(Uri uri) {
String rowId = uri.getLastPathSegment();
String[] columns = new String[] {
DictionaryDatabase.KEY_WORD,
DictionaryDatabase.KEY_DEFINITION};
return mDictionary.getWord(rowId, columns);
}
private Cursor refreshShortcut(Uri uri) {
/* This won't be called with the current implementation, but if we include
* {@link SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} as a column in our suggestions table, we
* could expect to receive refresh queries when a shortcutted suggestion is displayed in
* Quick Search Box. In which case, this method will query the table for the specific
* word, using the given item Uri and provide all the columns originally provided with the
* suggestion query.
*/
String rowId = uri.getLastPathSegment();
String[] columns = new String[] {
BaseColumns._ID,
DictionaryDatabase.KEY_WORD,
DictionaryDatabase.KEY_DEFINITION,
SearchManager.SUGGEST_COLUMN_SHORTCUT_ID,
SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID};
return mDictionary.getWord(rowId, columns);
}
/**
* This method is required in order to query the supported types.
* It's also useful in our own query() method to determine the type of Uri received.
*/
@Override
public String getType(Uri uri) {
switch (sURIMatcher.match(uri)) {
case SEARCH_WORDS:
return WORDS_MIME_TYPE;
case GET_WORD:
return DEFINITION_MIME_TYPE;
case SEARCH_SUGGEST:
return SearchManager.SUGGEST_MIME_TYPE;
case REFRESH_SHORTCUT:
return SearchManager.SHORTCUT_MIME_TYPE;
default:
throw new IllegalArgumentException("Unknown URL " + uri);
}
}