Android saves the database to the SD card, android database SD card

Source: Internet
Author: User

Android saves the database to the SD card, android database SD card

Zookeeper sometimes saves the database to external storage or SD card (in this case, data can be encrypted to prevent data cracking) for the sake of needs. For example, an application supports multiple data, each data must have a corresponding database, and the amount of information in the database is very large. This should obviously store the database in external storage or SD card, because the RAM size is limited; then, when writing some test programs, save the database on the SD card to make it easier to view the content in the database.

When using SQLiteOpenHelper to create a database, Android saves the database in the '/data/Application name/databases' directory by default, you only need to input the database name in the constructor that inherits the SQLiteOpenHelper class. However, if you save the database to the specified path, you must override the context in the constructor that inherits the SQLiteOpenHelper class, because: Read SQLiteOpenHelper. java source code will find that the database creation is implemented through the openOrCreateDatabase method of Context. If we need to create a database under the specified path, we need to write a class to inherit the Context, rewrite the openOrCreateDatabase method and specify the database storage path in the openOrCreateDatabase method. The following are getWritableDatabase and getRea in SQLiteOpenHelper. The source code of the dableDatabase method. SQLiteOpenHelper creates a database using 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 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();        }    }


Using the above analysis, Zookeeper can write a custom Context class that inherits the Context. However, since there are other Abstract Functions in the Context except the openOrCreateDatabase method, we recommend that you use a non-abstract class ContextWrapper, this class inherits 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 not, create the object * @ param name * @ param mode * @ param factory */@ Override public File getDatabasePath (String name) {// determine whether the SD card boolean sdExist = android exists. OS. environment. MEDIA_MOUNTED.equals (android. OS. environment. getExternalStorageState (); if (! SdExist) {// if it does not exist, return null;} else {// if it exists // obtain the SD card path String dbDir = FileUtils. getFlashBPath (); dbDir + = "DB"; // database directory String dbPath = dbDir + "/" + name; // database path // determine whether the directory exists, if the directory does not exist, create File dirFile = new File (dbDir); if (! DirFile. exists () {dirFile. mkdirs () ;}// whether the database File is successfully created boolean isFileCreateSuccess = false; // if the File exists and does not exist, create the File dbFile = new File (dbPath ); if (! DbFile. exists () {try {isFileCreateSuccess = dbFile. createNewFile (); // create a file} catch (IOException e) {e. printStackTrace () ;}} else {isFileCreateSuccess = true;} // returns the database file object if (isFileCreateSuccess) {return dbFile;} else {return null ;}}} /*** this method is used to open the database on the SD card. android 2.3 and below will call this method. ** @ 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 calls this method to obtain the database. ** @ See android. content. contextWrapper # openOrCreateDatabase (java. lang. string, int, * android. database. sqlite. SQLiteDatabase. cursorFactory, * android. database. principal) * @ 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 that inherits the subclass of SQLiteOpenHelper, replace context with an instance of DatabaseContext:

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

Note:This article has largely referred to other articles on the internet, and I would like to thank the authors of these articles.

References:

  • Use SQLiteOpenHelper in Android to manage databases on the SD card

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.