How do I save a database to an SD card based on Android

  • 2020-12-05 17:22:15
  • OfStack

Sometimes to need, the database will be saved to the external storage or SD card (in this case can be cracked by encrypting data to avoid data), such as an application support multiple data, every data need to have a corresponding database, and database information particularly big, this is obviously more database should be stored in the external storage or SD card, because the size of the RAM is limited; Secondly, it is easier to view the contents of the database by keeping the database on the SD card when writing some test programs.

Android through SQLiteOpenHelper default is created when the database is the database is stored in the '/ data/data/application name/databases' directory, only need to inherit SQLiteOpenHelper class passed in the constructor of the name of the database is ok, but if the database is saved to the specified path below, all need to rewrite the inheritance SQLiteOpenHelper context in the constructor of a class, because, in the reading SQLiteOpenHelper. java source will find: Create the database by Context openOrCreateDatabase method, if we need to create the database under the specified path, you need to write a class inherits Context, and copy the openOrCreateDatabase method, database storage paths can be specified in the openOrCreateDatabase method, for the class below SQLiteOpenHelper getWritableDatabase and getReadableDatabase method source code, SQLiteOpenHelper is through these two methods to create the database.


/**
  * Create and/or open a database that will be used for reading and writing.
  * The first time this is called, the database will be opened and
  * {@link #onCreate}, {@link #onUpgrade} and/or {@link #onOpen} will be
  * called.
  *
  * <p>Once opened successfully, the database is cached, so you can
  * call this method every time you need to write to the database.
  * (Make sure to call {@link #close} when you no longer need the database.)
  * Errors such as bad permissions or a full disk may cause this method
  * to fail, but future attempts may succeed if the problem is fixed.</p>
  *
  * <p class="caution">Database upgrade may take a long time, you
  * should not call this method from the application main thread, including
  * from {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
  *
  * @throws SQLiteException if the database cannot be opened for writing
  * @return a read/write database object valid until {@link #close} is called
  */
 public synchronized SQLiteDatabase getWritableDatabase() {
  if (mDatabase != null) {
   if (!mDatabase.isOpen()) {
    // darn! the user closed the database by calling mDatabase.close()
    mDatabase = null;
   } else if (!mDatabase.isReadOnly()) {
    return mDatabase; // The database is already open for business
   }
  }
  if (mIsInitializing) {
   throw new IllegalStateException("getWritableDatabase called recursively");
  }
  // If we have a read-only database open, someone could be using it
  // (though they shouldn't), which would cause a lock to be held on
  // the file, and our attempts to open the database read-write would
  // fail waiting for the file lock. To prevent that, we acquire the
  // lock on the read-only database, which shuts out other users.
  boolean success = false;
  SQLiteDatabase db = null;
  if (mDatabase != null) mDatabase.lock();
  try {
   mIsInitializing = true;
   if (mName == null) {
    db = SQLiteDatabase.create(null);
   } else {
    db = mContext.openOrCreateDatabase(mName, 0, mFactory, mErrorHandler);
   }
   int version = db.getVersion();
   if (version != mNewVersion) {
    db.beginTransaction();
    try {
     if (version == 0) {
      onCreate(db);
     } else {
      if (version > mNewVersion) {
       onDowngrade(db, version, mNewVersion);
      } else {
       onUpgrade(db, version, mNewVersion);
      }
     }
     db.setVersion(mNewVersion);
     db.setTransactionSuccessful();
    } finally {
     db.endTransaction();
    }
   }
   onOpen(db);
   success = true;
   return db;
  } finally {
   mIsInitializing = false;
   if (success) {
    if (mDatabase != null) {
     try { mDatabase.close(); } catch (Exception e) { }
     mDatabase.unlock();
    }
    mDatabase = db;
   } else {
    if (mDatabase != null) mDatabase.unlock();
    if (db != null) db.close();
   }
  }
 }
 /**
  * Create and/or open a database. This will be the same object returned by
  * {@link #getWritableDatabase} unless some problem, such as a full disk,
  * requires the database to be opened read-only. In that case, a read-only
  * database object will be returned. If the problem is fixed, a future call
  * to {@link #getWritableDatabase} may succeed, in which case the read-only
  * database object will be closed and the read/write object will be returned
  * in the future.
  *
  * <p class="caution">Like {@link #getWritableDatabase}, this method may
  * take a long time to return, so you should not call it from the
  * application main thread, including from
  * {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
  *
  * @throws SQLiteException if the database cannot be opened
  * @return a database object valid until {@link #getWritableDatabase}
  * or {@link #close} is called.
  */
 public synchronized SQLiteDatabase getReadableDatabase() {
  if (mDatabase != null) {
   if (!mDatabase.isOpen()) {
    // darn! the user closed the database by calling mDatabase.close()
    mDatabase = null;
   } else {
    return mDatabase; // The database is already open for business
   }
  }
  if (mIsInitializing) {
   throw new IllegalStateException("getReadableDatabase called recursively");
  }
  try {
   return getWritableDatabase();
  } catch (SQLiteException e) {
   if (mName == null) throw e; // Can't open a temp database read-only!
   Log.e(TAG, "Couldn't open " + mName + " for writing (will try read-only):", e);
  }
  SQLiteDatabase db = null;
  try {
   mIsInitializing = true;
   String path = mContext.getDatabasePath(mName).getPath();
   db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY,
     mErrorHandler);
   if (db.getVersion() != mNewVersion) {
    throw new SQLiteException("Can't upgrade read-only database from version " +
      db.getVersion() + " to " + mNewVersion + ": " + path);
   }
   onOpen(db);
   Log.w(TAG, "Opened " + mName + " in read-only mode");
   mDatabase = db;
   return mDatabase;
  } finally {
   mIsInitializing = false;
   if (db != null && db != mDatabase) db.close();
  }
 }

Through the above analysis can write a custom Context class, this class can inherit from Context, but because Context has in addition to openOrCreateDatabase method other abstract functions, so it is recommended to use non-abstract class ContextWrapper, this class inherited from Context, custom DatabaseContext class source code is as follows:


public class DatabaseContext extends ContextWrapper {
 public DatabaseContext(Context context){
  super( context );
 }
 /**
  *  Gets the database path, or creates the object object if it does not exist 
  * @param name
  * @param mode
  * @param factory
  */
 @Override
 public File getDatabasePath(String name) {
  // To determine whether there is sd card 
  boolean sdExist = android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment.getExternalStorageState());
  if(!sdExist){// If it doesn't exist ,
   return null;
  }else{// If there is 
   // To obtain sd The card path 
   String dbDir= FileUtils.getFlashBPath();
   dbDir += "DB";// Database directory 
   String dbPath = dbDir+"/"+name;// Database path 
   // Determines whether a directory exists or creates it if it does not 
   File dirFile = new File(dbDir);
   if(!dirFile.exists()){
    dirFile.mkdirs();
   }
   // Whether the database file was created successfully 
   boolean isFileCreateSuccess = false; 
   // Determines if the file exists or creates it if it doesn't 
   File dbFile = new File(dbPath);
   if(!dbFile.exists()){
    try {   
     isFileCreateSuccess = dbFile.createNewFile();// Create a file 
    } catch (IOException e) {
     e.printStackTrace();
    }
   }else{
    isFileCreateSuccess = true;
   }
   // Returns a database file object 
   if(isFileCreateSuccess){
    return dbFile;
   }else{
    return null;
   }
  }
 }
 /**
  *  Overloading this method is used to open SD Of the database on the card, android 2.3 This method is called. 
  * 
  * @param name
  * @param mode
  * @param factory
  */
 @Override
 public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) {
  SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null);
  return result;
 }
 /**
  * Android 4.0 This method is called to get the database. 
  * 
  * @see android.content.ContextWrapper#openOrCreateDatabase(java.lang.String, int, 
  *   android.database.sqlite.SQLiteDatabase.CursorFactory,
  *   android.database.DatabaseErrorHandler)
  * @param name
  * @param mode
  * @param factory
  * @param errorHandler
  */
 @Override
 public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory, DatabaseErrorHandler errorHandler) {
  SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null);
  return result;
 }
}

In the constructor of a subclass that inherits SQLiteOpenHelper, replace context with an instance of DatabaseContext:


DatabaseContext dbContext = new DatabaseContext(context);
super(dbContext, mDatabaseName, null, VERSION);

Based on Android how to save the database to SD card all the content to tell you so much, and also thank you very much for 1 since the site's website support, thank you.


Related articles: