title: Android SQLite DB in SD Card
body: <p><strong>SOLUTION</strong></p>
  
  <h2>I had to override the getReadableDatabase() and getWritableDatabase() in my custom DBHelper class.</h2>
  
  <p>I am facing a unique kind of problem.</p>
  
  <p>Until now, I have written Android apps that have used one SQLite DB internally on the phone memory, and it works perfectly. Now I wanted to add another DB and wanted to store it on the SD card. I did this by modifying the DatabaseHelper class that we usually use. I have also written a script that transfers the db from the assets folder to the SD card for one DB and the internal memory location for another.</p>
  
  <p>Now the problem that I am facing is that when I try to access the external DB, android creates an internal DB in the /data/data/package_name/databases folder and thus I end up getting <strong>no such table exception</strong>.</p>
  
  <p>Can someone tell me why I am getting this error!</p>
  
  <hr>
  
  <p><strong>Edit 1</strong>
  My DB Helper Class</p>
  
  <pre><code>public class DBHelper extends SQLiteOpenHelper {
  private Context myContext;
  private String DB_PATH;
  private String DB_NAME;
  private boolean isExternal;
  private SQLiteDatabase myDataBase;
  
  private final String TAG = "ERROR";
  
  public DBHelper(Context AppC, String DB_NAME, boolean isExternal,
          int DB_VERSION) {
      super(AppC, DB_NAME + ".sqlite", null, DB_VERSION);
      this.myContext = AppC;
      this.isExternal = isExternal;
      this.DB_NAME = DB_NAME;
      setDbPath();
  }
  
  private void setDbPath() {
      if (this.isExternal) {
          try {
              DB_PATH = Environment.getExternalStorageDirectory()
                      + "/myappname/";
          } catch (Exception e) {
              DB_PATH = "/mnt/sdcard/myappname/";
          }
      } else {
          try {
              DB_PATH = Environment.getDataDirectory()
                      + "/data/my.app.package/databases/";
          } catch (Exception e) {
              DB_PATH = "data/data/my.app.package/databases/";
          }
      }
  }
  
  /**
   * Creates a empty database on the system and rewrites it with your own
   * database.
   * */
  public void createDataBase() throws IOException {
      boolean dbExist = checkDataBase();
      if (!dbExist) {
          try {
              copyDataBase();
          } catch (Exception E) {
              // MRC
          }
      }
  }
  
  /**
   * Copies your database from your local assets-folder to the just created
   * empty database in the system folder, from where it can be accessed and
   * handled. This is done by transferring byte streams.
   * */
  private void copyDataBase() throws IOException {
      String filePath = DB_PATH + this.DB_NAME + ".sqlite";
  
      if (this.isExternal) {
          File file = new File(filePath);
          if (!file.exists()) {
              File dir = new File(DB_PATH);
              if (dir.exists() || dir.mkdirs()) {
                  transferFromAssets(this.DB_NAME + ".zip", filePath);
              } else {
                  Log.d(TAG, "Unable to create dir " + DB_PATH);
              }
          }
      } else {
          // By calling this method and empty database will be created
          // into the default system path of your application so we
          // will be able to overwrite that database with our
          // database.
  
          SQLiteDatabase db_Read = this.getReadableDatabase();
          db_Read.close();
          transferFromAssets(this.DB_NAME + ".zip", filePath);
      }
  }
  
  private void transferFromAssets(String from, String to) throws IOException {
      ZipInputStream myInput = new ZipInputStream(myContext.getAssets().open(
              from));
      myInput.getNextEntry(); // Open the empty db as the output stream
      OutputStream myOutput = new FileOutputStream(to);
      // transfer bytes from the inputfile to the outputfile
      AndroidUtil.copyStream(myInput, myOutput);
  }
  
  /**
   * Check if the database already exist to avoid re-copying the file each
   * time you open the application.
   * 
   * @return true if it exists, false if it doesn't
   */
  private boolean checkDataBase() {
      File dbFile = new File(DB_PATH + this.DB_NAME + ".sqlite");
      return dbFile.exists();
  }
  
  public void openDataBase() throws SQLException {
      String myPath = DB_PATH + this.DB_NAME + ".sqlite";
      Log.d(TAG, "Opening DB:" + myPath);
      myDataBase = SQLiteDatabase.openDatabase(myPath, null,
              SQLiteDatabase.OPEN_READWRITE);
  }
  
  @Override
  public synchronized void close() {
      if (myDataBase != null)
          myDataBase.close();
      super.close();
  }
  
  public void onCreate(SQLiteDatabase db) {
  
  }
  
  @Override
  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  
  }
  
  }
  </code></pre>
  
  <p>*<em>My Internal Memory DB's class's constructor *</em></p>
  
  <pre><code>public WordsDB(Context AppC) {
      DBAPI = new DBHelper(AppC, "DB_NAME", false, 11);
      this.AppC = AppC;
      try {
          DBAPI.createDataBase();
          DBAPI.openDataBase();
      } catch (IOException e) {
          CustomToast.Toast(AppC, "", TCategory_E.CRITICAL_ERROR,
                  TDuration_E.LONG, TPosition_E.CENTER);
          // MRC
      }
  }
  </code></pre>
  
  <p>** My External DB class's constructor **</p>
  
  <pre><code>public BackupDB(Context AppC) {
      DBAPI = new DBHelper(AppC, "/mnt/sdcard/myapp/backup-db",
              true, 11);
      this.AppC = AppC;
      try {
          DBAPI.createDataBase();
          DBAPI.openDataBase();
      } catch (IOException e) {
          CustomToast.Toast(AppC, "", TCategory_E.CRITICAL_ERROR,
                  TDuration_E.LONG, TPosition_E.CENTER);
          // MRC
      }
  }
  </code></pre>
  
  <p><strong>Edit 2</strong></p>
  
  <p>The function in the external DB's helper class that leads to the error:</p>
  
  <pre><code>public void setValue(int No, int Stars) {
      try {
          ContentValues update = new ContentValues();
          update.put(COL_STARRED, Stars);
          String args[] = { No + "" };
          SQLDB = DBAPI.getWritableDatabase();
          SQLDB.acquireReference();
          SQLDB.update(TABLE_NAME, update, COL_ID + "=?", args);
          SQLDB.releaseReference();
          SQLDB.close();
      } catch (Exception E) {
          Log.d(TAG, E.getMessage());
      }
  }
  </code></pre>
  
  <p>If I try to use the external DB as an internal DB, there is no error which leads me to think that there is something wrong that I am doing for an external DB.</p>