diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 43a44221d2270702c93fa843a787d29937af1def..30c2dfedbb925f804bf0f72f4221cda7b1b93a4a 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -89,6 +89,8 @@ public final class BinaryDictionary extends Dictionary {
     private final long mDictSize;
     private final String mDictFilePath;
     private final boolean mIsUpdatable;
+    private boolean mHasUpdated;
+
     private final int[] mInputCodePoints = new int[MAX_WORD_LENGTH];
     private final int[] mOutputSuggestionCount = new int[1];
     private final int[] mOutputCodePoints = new int[MAX_WORD_LENGTH * MAX_RESULTS];
@@ -138,6 +140,7 @@ public final class BinaryDictionary extends Dictionary {
         mDictSize = length;
         mDictFilePath = filename;
         mIsUpdatable = isUpdatable;
+        mHasUpdated = false;
         mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance);
         loadDictionary(filename, offset, length, isUpdatable);
     }
@@ -185,6 +188,7 @@ public final class BinaryDictionary extends Dictionary {
     // TODO: Move native dict into session
     private final void loadDictionary(final String path, final long startOffset,
             final long length, final boolean isUpdatable) {
+        mHasUpdated = false;
         mNativeDict = openNative(path, startOffset, length, isUpdatable);
     }
 
@@ -401,6 +405,7 @@ public final class BinaryDictionary extends Dictionary {
                 StringUtils.toCodePointArray(shortcutTarget) : null;
         addUnigramWordNative(mNativeDict, codePoints, probability, shortcutTargetCodePoints,
                 shortcutProbability, isNotAWord, isBlacklisted, timestamp);
+        mHasUpdated = true;
     }
 
     // Add a bigram entry to binary dictionary with timestamp in native code.
@@ -412,6 +417,7 @@ public final class BinaryDictionary extends Dictionary {
         final int[] codePoints0 = StringUtils.toCodePointArray(word0);
         final int[] codePoints1 = StringUtils.toCodePointArray(word1);
         addBigramWordsNative(mNativeDict, codePoints0, codePoints1, probability, timestamp);
+        mHasUpdated = true;
     }
 
     // Remove a bigram entry form binary dictionary in native code.
@@ -422,6 +428,7 @@ public final class BinaryDictionary extends Dictionary {
         final int[] codePoints0 = StringUtils.toCodePointArray(word0);
         final int[] codePoints1 = StringUtils.toCodePointArray(word1);
         removeBigramWordsNative(mNativeDict, codePoints0, codePoints1);
+        mHasUpdated = true;
     }
 
     public void addMultipleDictionaryEntries(final LanguageModelParam[] languageModelParams) {
@@ -433,6 +440,7 @@ public final class BinaryDictionary extends Dictionary {
             }
             processedParamCount = addMultipleDictionaryEntriesNative(mNativeDict,
                     languageModelParams, processedParamCount);
+            mHasUpdated = true;
             if (processedParamCount <= 0) {
                 return;
             }
@@ -451,8 +459,10 @@ public final class BinaryDictionary extends Dictionary {
 
     public void flush() {
         if (!isValidDictionary()) return;
-        flushNative(mNativeDict, mDictFilePath);
-        reopen();
+        if (mHasUpdated) {
+            flushNative(mNativeDict, mDictFilePath);
+            reopen();
+        }
     }
 
     public void flushWithGC() {
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
index 4e17f83895231653ef56fba18550c83161f6a70d..d5873d70fcd22042ee1c9434570ae4d8c8ac0694 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -100,10 +100,6 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
                 });
     }
 
-    public void reopen(final Context context) {
-        registerObserver(context);
-    }
-
     @Override
     public synchronized void close() {
         if (mObserver != null) {
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index aea4811a9709889c02c0d28eb45ca7efcaa44274..64e9d2b51ff080f10ffd71302e3a8e553ebfb6a7 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -262,6 +262,9 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
         ExecutorUtils.getExecutor(mDictName).execute(new Runnable() {
             @Override
             public void run() {
+                if (mBinaryDictionary == null) {
+                    return;
+                }
                 runGCAfterAllPrioritizedTasksIfRequiredLocked(mindsBlockByGC);
             }
         });
@@ -274,9 +277,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
     }
 
     private void runGCAfterAllPrioritizedTasksIfRequiredLocked(final boolean mindsBlockByGC) {
-        if (mBinaryDictionary == null) {
-            return;
-        }
         // needsToRunGC() have to be called with lock.
         if (mBinaryDictionary.needsToRunGC(mindsBlockByGC)) {
             if (setProcessingLargeTaskIfNot()) {
@@ -301,9 +301,13 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
     protected void addWordDynamically(final String word, final int frequency,
             final String shortcutTarget, final int shortcutFreq, final boolean isNotAWord,
             final boolean isBlacklisted, final int timestamp) {
+        reloadDictionaryIfRequired();
         ExecutorUtils.getExecutor(mDictName).execute(new Runnable() {
             @Override
             public void run() {
+                if (mBinaryDictionary == null) {
+                    return;
+                }
                 runGCAfterAllPrioritizedTasksIfRequiredLocked(true /* mindsBlockByGC */);
                 addWordDynamicallyLocked(word, frequency, shortcutTarget, shortcutFreq,
                         isNotAWord, isBlacklisted, timestamp);
@@ -323,9 +327,13 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
      */
     protected void addBigramDynamically(final String word0, final String word1,
             final int frequency, final int timestamp) {
+        reloadDictionaryIfRequired();
         ExecutorUtils.getExecutor(mDictName).execute(new Runnable() {
             @Override
             public void run() {
+                if (mBinaryDictionary == null) {
+                    return;
+                }
                 runGCAfterAllPrioritizedTasksIfRequiredLocked(true /* mindsBlockByGC */);
                 addBigramDynamicallyLocked(word0, word1, frequency, timestamp);
             }
@@ -341,9 +349,13 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
      * Dynamically remove a word bigram in the dictionary.
      */
     protected void removeBigramDynamically(final String word0, final String word1) {
+        reloadDictionaryIfRequired();
         ExecutorUtils.getExecutor(mDictName).execute(new Runnable() {
             @Override
             public void run() {
+                if (mBinaryDictionary == null) {
+                    return;
+                }
                 runGCAfterAllPrioritizedTasksIfRequiredLocked(true /* mindsBlockByGC */);
                 mBinaryDictionary.removeBigramWords(word0, word1);
             }
@@ -360,14 +372,15 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
     protected void addMultipleDictionaryEntriesDynamically(
             final ArrayList<LanguageModelParam> languageModelParams,
             final AddMultipleDictionaryEntriesCallback callback) {
+        reloadDictionaryIfRequired();
         ExecutorUtils.getExecutor(mDictName).execute(new Runnable() {
             @Override
             public void run() {
+                if (mBinaryDictionary == null) {
+                    return;
+                }
                 final boolean locked = setProcessingLargeTaskIfNot();
                 try {
-                    if (mBinaryDictionary == null) {
-                        return;
-                    }
                     mBinaryDictionary.addMultipleDictionaryEntries(
                             languageModelParams.toArray(
                                     new LanguageModelParam[languageModelParams.size()]));
diff --git a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java
index 6f84e1f10871d189c33901e30f206f98a92d7e93..712e314a82aed49d05a45c8a07fc7b1da98ff5e8 100644
--- a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java
+++ b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java
@@ -66,7 +66,7 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB
         }
         // Flush pending writes.
         flush();
-        // TODO: Quit depending on finalize() and really close the dictionary file.
+        super.close();
     }
 
     public void flush() {