Sometimes, for the sake of need, the database will be saved to an external storage or SD card (in this case, the data can be encrypted to avoid the data being cracked). For example, an application supports multiple data, and each data needs to have a corresponding database, and the amount of information in the database is particularly large, it is obvious that the database should be saved in an external storage or SD card, because the size of RAM is limited; secondly, saving the database in an SD card when writing certain test programs is more convenient to view the content in the database.
When Android creates a database through SQLiteOpenHelper, the database is saved in the '/data/data/application name/databases' directory. You only need to pass the database name into the constructor that inherits the SQLiteOpenHelper class. However, if you save the database to the specified path, you need to rewrite the context in the constructor that inherits the SQLiteOpenHelper class, because when reading the source code, you will find that the database is created through the openOrCrea of the Context. The teDatabase method is implemented. If we need to create a database under the specified path, we need to write a class inheritance Context and rewrite its openOrCreateDatabase method. The path to the database storage in the openOrCreateDatabase method is specified. The following is the source code of the getWritableDatabase and getReadableDatabase methods in the class SQLiteOpenHelper. SQLiteOpenHelper creates the database through these two methods.
/** * 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 #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 (!()) { // darn! the user closed the database by calling () mDatabase = null; } else if (!()) { 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) (); try { mIsInitializing = true; if (mName == null) { db = (null); } else { db = (mName, 0, mFactory, mErrorHandler); } int version = (); if (version != mNewVersion) { (); try { if (version == 0) { onCreate(db); } else { if (version > mNewVersion) { onDowngrade(db, version, mNewVersion); } else { onUpgrade(db, version, mNewVersion); } } (mNewVersion); (); } finally { (); } } onOpen(db); success = true; return db; } finally { mIsInitializing = false; if (success) { if (mDatabase != null) { try { (); } catch (Exception e) { } (); } mDatabase = db; } else { if (mDatabase != null) (); if (db != null) (); } } } /** * 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 #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 (!()) { // darn! the user closed the database by calling () 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! (TAG, "Couldn't open " + mName + " for writing (will try read-only):", e); } SQLiteDatabase db = null; try { mIsInitializing = true; String path = (mName).getPath(); db = (path, mFactory, SQLiteDatabase.OPEN_READONLY, mErrorHandler); if (() != mNewVersion) { throw new SQLiteException("Can't upgrade read-only database from version " + () + " to " + mNewVersion + ": " + path); } onOpen(db); (TAG, "Opened " + mName + " in read-only mode"); mDatabase = db; return mDatabase; } finally { mIsInitializing = false; if (db != null && db != mDatabase) (); } }
Through the above analysis, you can write a custom Context class, which can inherit Context. However, since there are other abstract functions in the Context except the openOrCreateDatabase method, it is recommended to use the non-abstract class ContextWrapper, which is inherited from Context. The source code of the custom DatabaseContext class is as follows:
public class DatabaseContext extends ContextWrapper { public DatabaseContext(Context context){ super( context ); } /** * Get the database path, if it does not exist, create an object object * @param name * @param mode * @param factory */ @Override public File getDatabasePath(String name) { //Judge whether there is an SD card boolean sdExist = .MEDIA_MOUNTED.equals(()); if(!sdExist){//If it does not exist, return null; }else{//If there is //Get the SD card path String dbDir= (); dbDir += "DB";//Directory where the database is located String dbPath = dbDir+"/"+name;//Database path //Display whether the directory exists. If it does not exist, create the directory File dirFile = new File(dbDir); if(!()){ (); } //Whether the database file is created successfully boolean isFileCreateSuccess = false; //Display whether the file exists. If it does not exist, create the file File dbFile = new File(dbPath); if(!()){ try { isFileCreateSuccess = ();//Create a file } catch (IOException e) { (); } }else{ isFileCreateSuccess = true; } //Return the database file object if(isFileCreateSuccess){ return dbFile; }else{ return null; } } } /** * Overload this method is used to open the database on the SD card. This method will be called in Android 2.3 and below. * * @param name * @param mode * @param factory */ @Override public SQLiteDatabase openOrCreateDatabase(String name, int mode, factory) { SQLiteDatabase result = (getDatabasePath(name), null); return result; } /** * Android 4.0 will call this method to get the database. * * @see #openOrCreateDatabase(, int, * , * ) * @param name * @param mode * @param factory * @param errorHandler */ @Override public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory, DatabaseErrorHandler errorHandler) { SQLiteDatabase result = (getDatabasePath(name), null); return result; } }
In the constructor of the subclass inheritance of SQLiteOpenHelper, use the instance of DatabaseContext to replace the context:
DatabaseContext dbContext = new DatabaseContext(context); super(dbContext, mDatabaseName, null, VERSION);
I will introduce all the contents of how to save the database to the SD card based on Android. I also very much thank you for your support for my website. Thank you.