title: Android SQLite database gets corrupted
body: <p>This link describes my problem exactly: <a href="http://old.nabble.com/Android-database-corruption-td28044218.html#a28044218" rel="noreferrer">http://old.nabble.com/Android-database-corruption-td28044218.html#a28044218</a></p>
  
  <p>There are about 300 people using my Android App right now and every once and while I get a crash report to the server with this stack trace:</p>
  
  <pre><code>android.database.sqlite.SQLiteDatabaseCorruptException: database disk image is malformed
      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2596)
      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2621)
      at android.app.ActivityThread.access$2200(ActivityThread.java:126)
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1932)
      at android.os.Handler.dispatchMessage(Handler.java:99)
      at android.os.Looper.loop(Looper.java:123)
      at android.app.ActivityThread.main(ActivityThread.java:4595)
      at java.lang.reflect.Method.invokeNative(Native Method)
      at java.lang.reflect.Method.invoke(Method.java:521)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
      at dalvik.system.NativeStart.main(Native Method) Caused by: android.database.sqlite.SQLiteDatabaseCorruptException: database disk image is malformed
      at android.database.sqlite.SQLiteQuery.native_fill_window(Native Method)
      at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:75)
      at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:295)
      at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:276)
      at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:171)
      at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:248)
  </code></pre>
  
  <p>The result is the app crashing and all the data in the DB being lost.</p>
  
  <p>One thing to note is that every time I read or write to the database I get a new SQLiteDatabase and close it as soon as I'm done.  I did this in an attempt to prevent these kind of corruption errors.</p>
  
  <p>I also tried synchronizing all DB reads and writes using a single static object and that didn't seem to help.</p>
  
  <p>Is it possible this is just a SQLite bug?</p>
  
  <p>I found a similar bug with the built-in email app here: <a href="http://code.google.com/p/android/issues/detail?id=5610" rel="noreferrer">http://code.google.com/p/android/issues/detail?id=5610</a>.</p>
  
  <p>Here is my code:</p>
  
  <pre><code>public class KeyValueTableAdapter extends BaseTableAdapter {
  
      private String tableName;
      private String keyColumnName;
      private String valueColumnName;
  
      public KeyValueTableAdapter(Context context, String tableName, String keyColumnName, String valueColumnName) {
          super(context);
          this.tableName = tableName;
          this.keyColumnName = keyColumnName;
          this.valueColumnName = valueColumnName;
      }
  
      protected String getStringValue(int key) {
          Cursor cursor = null;
          SQLiteDatabase db = null;
          String value;
  
          try {
              db = dbOpenHelper.getReadableDatabase();
              cursor = db.query(true, tableName, new String[] { valueColumnName }, keyColumnName + "=" + key, null, null, null, null, null);
  
              if ((cursor.getCount() == 0) || !cursor.moveToFirst()) {
                  value = null;
              } else {
                  value = cursor.getString(0);
              }
          } finally {
              if (cursor != null) cursor.close();
              if (db != null) db.close();
              dbOpenHelper.close();
          }
  
          return value;
      }
  }
  
  
  public abstract class BaseTableAdapter {
  
      protected DbOpenHelper dbOpenHelper;
  
      public BaseTableAdapter(Context context) {
          this.dbOpenHelper = new DbOpenHelper(context, DatabaseSettings.DATABASE_NAME, null, DatabaseSettings.DATABASE_VERSION);
      }
  
  }
  </code></pre>