Merge "Load UserDictionary and AutoDictionary in a background thread."

main
Amith Yamasani 2010-03-10 12:59:16 -08:00 committed by Android (Google) Code Review
commit 21daa53245
4 changed files with 94 additions and 87 deletions

View File

@ -96,11 +96,14 @@ public class AutoDictionary extends ExpandableDictionary {
return frequency >= VALIDITY_THRESHOLD;
}
@Override
public void close() {
mOpenHelper.close();
super.close();
}
private void loadDictionary() {
@Override
public void loadDictionaryAsync() {
// Load the words that correspond to the current input locale
Cursor cursor = query(COLUMN_LOCALE + "=?", new String[] { mLocale });
if (cursor.moveToFirst()) {
@ -183,15 +186,6 @@ public class AutoDictionary extends ExpandableDictionary {
return c;
}
private boolean insert(ContentValues values) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long rowId = db.insert(AUTODICT_TABLE_NAME, Words.WORD, values);
if (rowId > 0) {
return true;
}
return false;
}
private int delete(String where, String[] whereArgs) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count = db.delete(AUTODICT_TABLE_NAME, where, whereArgs);

View File

@ -35,15 +35,8 @@ public class ContactsDictionary extends ExpandableDictionary {
private ContentObserver mObserver;
private boolean mRequiresReload;
private long mLastLoadedContacts;
private boolean mUpdatingContacts;
// Use this lock before touching mUpdatingContacts & mRequiresDownload
private Object mUpdatingLock = new Object();
public ContactsDictionary(Context context) {
super(context);
// Perform a managed query. The Activity will handle closing and requerying the cursor
@ -53,15 +46,10 @@ public class ContactsDictionary extends ExpandableDictionary {
cres.registerContentObserver(Contacts.CONTENT_URI, true, mObserver = new ContentObserver(null) {
@Override
public void onChange(boolean self) {
synchronized (mUpdatingLock) {
mRequiresReload = true;
}
setRequiresReload(true);
}
});
synchronized (mUpdatingLock) {
loadDictionaryAsyncLocked();
}
loadDictionary();
}
public synchronized void close() {
@ -69,41 +57,26 @@ public class ContactsDictionary extends ExpandableDictionary {
getContext().getContentResolver().unregisterContentObserver(mObserver);
mObserver = null;
}
super.close();
}
private synchronized void loadDictionaryAsyncLocked() {
@Override
public void startDictionaryLoadingTaskLocked() {
long now = SystemClock.uptimeMillis();
if (mLastLoadedContacts == 0
|| now - mLastLoadedContacts > 30 * 60 * 1000 /* 30 minutes */) {
if (!mUpdatingContacts) {
mUpdatingContacts = true;
mRequiresReload = false;
new LoadContactsTask().execute();
}
super.startDictionaryLoadingTaskLocked();
}
}
@Override
public synchronized void getWords(final WordComposer codes, final WordCallback callback,
int[] nextLettersFrequencies) {
synchronized (mUpdatingLock) {
// If we need to update, start off a background task
if (mRequiresReload) loadDictionaryAsyncLocked();
// Currently updating contacts, don't return any results.
if (mUpdatingContacts) return;
public void loadDictionaryAsync() {
Cursor cursor = getContext().getContentResolver()
.query(Contacts.CONTENT_URI, PROJECTION, null, null, null);
if (cursor != null) {
addWords(cursor);
}
super.getWords(codes, callback, nextLettersFrequencies);
}
@Override
public synchronized boolean isValidWord(CharSequence word) {
synchronized (mUpdatingLock) {
// If we need to update, start off a background task
if (mRequiresReload) loadDictionaryAsyncLocked();
if (mUpdatingContacts) return false;
}
return super.isValidWord(word);
mLastLoadedContacts = SystemClock.uptimeMillis();
}
private void addWords(Cursor cursor) {
@ -150,27 +123,5 @@ public class ContactsDictionary extends ExpandableDictionary {
}
cursor.close();
}
private class LoadContactsTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... v) {
Cursor cursor = getContext().getContentResolver()
.query(Contacts.CONTENT_URI, PROJECTION, null, null, null);
if (cursor != null) {
addWords(cursor);
}
mLastLoadedContacts = SystemClock.uptimeMillis();
return null;
}
@Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
synchronized (mUpdatingLock) {
mUpdatingContacts = false;
}
super.onPostExecute(result);
}
}
}

View File

@ -16,7 +16,11 @@
package com.android.inputmethod.latin;
import com.android.inputmethod.latin.Dictionary.WordCallback;
import android.content.Context;
import android.os.AsyncTask;
import android.os.SystemClock;
/**
* Base class for an in-memory dictionary that can grow dynamically and can
@ -32,6 +36,13 @@ public class ExpandableDictionary extends Dictionary {
public static final int MAX_WORD_LENGTH = 32;
private static final char QUOTE = '\'';
private boolean mRequiresReload;
private boolean mUpdatingDictionary;
// Use this lock before touching mUpdatingDictionary & mRequiresDownload
private Object mUpdatingLock = new Object();
static class Node {
char code;
int frequency;
@ -70,6 +81,34 @@ public class ExpandableDictionary extends Dictionary {
mCodes = new int[MAX_WORD_LENGTH][];
}
public void loadDictionary() {
synchronized (mUpdatingLock) {
startDictionaryLoadingTaskLocked();
}
}
public void startDictionaryLoadingTaskLocked() {
if (!mUpdatingDictionary) {
mUpdatingDictionary = true;
mRequiresReload = false;
new LoadDictionaryTask().execute();
}
}
public void setRequiresReload(boolean reload) {
synchronized (mUpdatingLock) {
mRequiresReload = reload;
}
}
public boolean getRequiresReload() {
return mRequiresReload;
}
/** Override to load your dictionary here, on a background thread. */
public void loadDictionaryAsync() {
}
Context getContext() {
return mContext;
}
@ -119,6 +158,13 @@ public class ExpandableDictionary extends Dictionary {
@Override
public void getWords(final WordComposer codes, final WordCallback callback,
int[] nextLettersFrequencies) {
synchronized (mUpdatingLock) {
// If we need to update, start off a background task
if (mRequiresReload) startDictionaryLoadingTaskLocked();
// Currently updating contacts, don't return any results.
if (mUpdatingDictionary) return;
}
mInputLength = codes.size();
mNextLettersFrequencies = nextLettersFrequencies;
if (mCodes.length < mInputLength) mCodes = new int[mInputLength][];
@ -135,6 +181,11 @@ public class ExpandableDictionary extends Dictionary {
@Override
public synchronized boolean isValidWord(CharSequence word) {
synchronized (mUpdatingLock) {
// If we need to update, start off a background task
if (mRequiresReload) startDictionaryLoadingTaskLocked();
if (mUpdatingDictionary) return false;
}
final int freq = getWordFrequencyRec(mRoots, word, 0, word.length());
return freq > -1;
}
@ -277,6 +328,24 @@ public class ExpandableDictionary extends Dictionary {
mRoots = new NodeArray();
}
private class LoadDictionaryTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... v) {
loadDictionaryAsync();
return null;
}
@Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
synchronized (mUpdatingLock) {
mUpdatingDictionary = false;
}
super.onPostExecute(result);
}
}
static char toLowerCase(char c) {
if (c < BASE_CHARS.length) {
c = BASE_CHARS[c];

View File

@ -16,16 +16,11 @@
package com.android.inputmethod.latin;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.provider.UserDictionary.Words;
public class UserDictionary extends ExpandableDictionary {
@ -40,8 +35,6 @@ public class UserDictionary extends ExpandableDictionary {
private static final int INDEX_FREQUENCY = 2;
private ContentObserver mObserver;
private boolean mRequiresReload;
private String mLocale;
public UserDictionary(Context context, String locale) {
@ -54,26 +47,27 @@ public class UserDictionary extends ExpandableDictionary {
cres.registerContentObserver(Words.CONTENT_URI, true, mObserver = new ContentObserver(null) {
@Override
public void onChange(boolean self) {
mRequiresReload = true;
setRequiresReload(true);
}
});
loadDictionary();
}
public synchronized void close() {
if (mObserver != null) {
getContext().getContentResolver().unregisterContentObserver(mObserver);
mObserver = null;
}
super.close();
}
private synchronized void loadDictionary() {
@Override
public void loadDictionaryAsync() {
Cursor cursor = getContext().getContentResolver()
.query(Words.CONTENT_URI, PROJECTION, "(locale IS NULL) or (locale=?)",
new String[] { mLocale }, null);
addWords(cursor);
mRequiresReload = false;
}
/**
@ -86,7 +80,8 @@ public class UserDictionary extends ExpandableDictionary {
*/
@Override
public synchronized void addWord(String word, int frequency) {
if (mRequiresReload) loadDictionary();
// Force load the dictionary here synchronously
if (getRequiresReload()) loadDictionaryAsync();
// Safeguard against adding long words. Can cause stack overflow.
if (word.length() >= getMaxWordLength()) return;
@ -101,19 +96,17 @@ public class UserDictionary extends ExpandableDictionary {
getContext().getContentResolver().insert(Words.CONTENT_URI, values);
// In case the above does a synchronous callback of the change observer
mRequiresReload = false;
setRequiresReload(false);
}
@Override
public synchronized void getWords(final WordComposer codes, final WordCallback callback,
int[] nextLettersFrequencies) {
if (mRequiresReload) loadDictionary();
super.getWords(codes, callback, nextLettersFrequencies);
}
@Override
public synchronized boolean isValidWord(CharSequence word) {
if (mRequiresReload) loadDictionary();
return super.isValidWord(word);
}