Separate executor for the Spelling decoder.

Bug 19710676.

Change-Id: I6e66eddd507c11e424105869833fe6841b90275d
main
Dan Zivkovic 2015-03-12 17:06:48 -07:00
parent 26fb83c481
commit eaa710d4aa
6 changed files with 54 additions and 20 deletions

View File

@ -56,8 +56,8 @@ public class ContactsContentObserver implements Runnable {
mContentObserver = new ContentObserver(null /* handler */) { mContentObserver = new ContentObserver(null /* handler */) {
@Override @Override
public void onChange(boolean self) { public void onChange(boolean self) {
// TODO(zivkovic): Schedule a separate task to reset the decoder. ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD)
ExecutorUtils.getBackgroundExecutor().execute(ContactsContentObserver.this); .execute(ContactsContentObserver.this);
} }
}; };
final ContentResolver contentResolver = mContext.getContentResolver(); final ContentResolver contentResolver = mContext.getContentResolver();

View File

@ -338,7 +338,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
final Locale locale, final DictionaryInitializationListener listener) { final Locale locale, final DictionaryInitializationListener listener) {
final CountDownLatch latchForWaitingLoadingMainDictionary = new CountDownLatch(1); final CountDownLatch latchForWaitingLoadingMainDictionary = new CountDownLatch(1);
mLatchForWaitingLoadingMainDictionaries = latchForWaitingLoadingMainDictionary; mLatchForWaitingLoadingMainDictionaries = latchForWaitingLoadingMainDictionary;
ExecutorUtils.getBackgroundExecutor().execute(new Runnable() { ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute(new Runnable() {
@Override @Override
public void run() { public void run() {
doReloadUninitializedMainDictionaries( doReloadUninitializedMainDictionaries(

View File

@ -168,7 +168,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
} }
private static void asyncExecuteTaskWithLock(final Lock lock, final Runnable task) { private static void asyncExecuteTaskWithLock(final Lock lock, final Runnable task) {
ExecutorUtils.getBackgroundExecutor().execute(new Runnable() { ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute(new Runnable() {
@Override @Override
public void run() { public void run() {
lock.lock(); lock.lock();

View File

@ -143,8 +143,8 @@ public class UserDictionaryLookup implements Closeable {
} }
// Schedule a new reload after RELOAD_DELAY_MS. // Schedule a new reload after RELOAD_DELAY_MS.
mReloadFuture = ExecutorUtils.getBackgroundExecutor().schedule( mReloadFuture = ExecutorUtils.getBackgroundExecutor(ExecutorUtils.SPELLING)
mLoader, RELOAD_DELAY_MS, TimeUnit.MILLISECONDS); .schedule(mLoader, RELOAD_DELAY_MS, TimeUnit.MILLISECONDS);
} }
} }
private final ContentObserver mObserver = new UserDictionaryContentObserver(); private final ContentObserver mObserver = new UserDictionaryContentObserver();
@ -186,7 +186,7 @@ public class UserDictionaryLookup implements Closeable {
// Schedule the initial load to run immediately. It's possible that the first call to // Schedule the initial load to run immediately. It's possible that the first call to
// isValidWord occurs before the dictionary has actually loaded, so it should not // isValidWord occurs before the dictionary has actually loaded, so it should not
// assume that the dictionary has been loaded. // assume that the dictionary has been loaded.
ExecutorUtils.getBackgroundExecutor().execute(mLoader); ExecutorUtils.getBackgroundExecutor(ExecutorUtils.SPELLING).execute(mLoader);
// Register the observer to be notified on changes to the UserDictionary and all individual // Register the observer to be notified on changes to the UserDictionary and all individual
// items. // items.

View File

@ -33,17 +33,30 @@ public class ExecutorUtils {
private static final String TAG = "ExecutorUtils"; private static final String TAG = "ExecutorUtils";
private static ScheduledExecutorService sExecutorService = public static final String KEYBOARD = "Keyboard";
Executors.newSingleThreadScheduledExecutor(new ExecutorFactory()); public static final String SPELLING = "Spelling";
private static ScheduledExecutorService sKeyboardExecutorService = newExecutorService(KEYBOARD);
private static ScheduledExecutorService sSpellingExecutorService = newExecutorService(SPELLING);
private static ScheduledExecutorService newExecutorService(final String name) {
return Executors.newSingleThreadScheduledExecutor(new ExecutorFactory(name));
}
private static class ExecutorFactory implements ThreadFactory { private static class ExecutorFactory implements ThreadFactory {
private final String mName;
private ExecutorFactory(final String name) {
mName = name;
}
@Override @Override
public Thread newThread(final Runnable runnable) { public Thread newThread(final Runnable runnable) {
Thread thread = new Thread(runnable, TAG); Thread thread = new Thread(runnable, TAG);
thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() { thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override @Override
public void uncaughtException(Thread thread, Throwable ex) { public void uncaughtException(Thread thread, Throwable ex) {
Log.w(TAG + "-" + runnable.getClass().getSimpleName(), ex); Log.w(mName + "-" + runnable.getClass().getSimpleName(), ex);
} }
}); });
return thread; return thread;
@ -64,24 +77,44 @@ public class ExecutorUtils {
// //
/** /**
* @param name Executor's name.
* @return scheduled executor service used to run background tasks * @return scheduled executor service used to run background tasks
*/ */
public static ScheduledExecutorService getBackgroundExecutor() { public static ScheduledExecutorService getBackgroundExecutor(final String name) {
if (sExecutorServiceForTests != null) { if (sExecutorServiceForTests != null) {
return sExecutorServiceForTests; return sExecutorServiceForTests;
} }
return sExecutorService; switch (name) {
case KEYBOARD:
return sKeyboardExecutorService;
case SPELLING:
return sSpellingExecutorService;
default:
throw new IllegalArgumentException("Invalid executor: " + name);
}
} }
public static void killTasks() { public static void killTasks(final String name) {
getBackgroundExecutor().shutdownNow(); final ScheduledExecutorService executorService = getBackgroundExecutor(name);
executorService.shutdownNow();
try { try {
getBackgroundExecutor().awaitTermination(5, TimeUnit.SECONDS); executorService.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.wtf(TAG, "Failed to shut down background task."); Log.wtf(TAG, "Failed to shut down: " + name);
throw new IllegalStateException("Failed to shut down background task."); }
} finally { if (executorService == sExecutorServiceForTests) {
sExecutorService = Executors.newSingleThreadScheduledExecutor(new ExecutorFactory()); // Don't do anything to the test service.
return;
}
switch (name) {
case KEYBOARD:
sKeyboardExecutorService = newExecutorService(KEYBOARD);
break;
case SPELLING:
sSpellingExecutorService = newExecutorService(SPELLING);
break;
default:
throw new IllegalArgumentException("Invalid executor: " + name);
} }
} }

View File

@ -35,7 +35,8 @@ public class ExecutorUtilsTests extends AndroidTestCase {
private static final int DELAY_FOR_WAITING_TASKS_MILLISECONDS = 500; private static final int DELAY_FOR_WAITING_TASKS_MILLISECONDS = 500;
public void testExecute() { public void testExecute() {
final ExecutorService executor = ExecutorUtils.getBackgroundExecutor(); final ExecutorService executor =
ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD);
final AtomicInteger v = new AtomicInteger(0); final AtomicInteger v = new AtomicInteger(0);
for (int i = 0; i < NUM_OF_TASKS; ++i) { for (int i = 0; i < NUM_OF_TASKS; ++i) {
executor.execute(new Runnable() { executor.execute(new Runnable() {