?? Sometimes the database is saved to an external storage or SD card for your needs (this can be done by encrypting data to prevent data from being cracked), such as an application that supports multiple data, every data needs a corresponding database, and the amount of information in the database is particularly large. This should obviously save the database in an external storage or SD card because the size of the RAM is limited, and secondly, it is easier to view the contents of the database by saving the database on the SD card when writing certain test programs.
?? By default when Android creates a database from Sqliteopenhelper, the database is saved in the '/data/data/Application name/databases ' directory, It is only necessary to pass in the database name in the constructor that inherits the Sqliteopenhelper class, but if you save the database under the specified path, you need to override the context in the constructor of the Sqliteopenhelper class by overriding the Because: in reading the source code of Sqliteopenhelper.java will find: the creation of the database is through the context of the Openorcreatedatabase method, if we need to create a database under the specified path, we need to write a class to inherit the context, and to replicate its ope Norcreatedatabase method, specify the path to the database store in the Openorcreatedatabase method, The following is the source code for Getwritabledatabase and Getreadabledatabase methods in class Sqliteopenhelper, and Sqliteopenhelper is to create the database by these two methods.
/** * Create and/or open a database that would be is used for reading and writing. * The first time this is called, the database would be opened and * {@link #onCreate}, {@link #onUpgrade} and/or {@link #onOpen} 'll be * called. * * * * <p>once opened successfully, the database is cached, so can * call this method every time you need t o Write to the database. * (make sure to call {@link #close} when longer need the database.) * Errors such as bad permissions or a full disk could cause this method * to fail, but the future attempts may succeed if th E problem is fixed.</p> * * <p class= "Caution" >database upgrade could take a long time, you * should The "not" method from the application main thread, including * from {@link Android.content.contentprovider#oncrea Te contentprovider.oncreate ()}. * * @throws Sqliteexception If the database cannot is opened for writing * @return a read/write database object va LID until {@link #close} is called */public synchronized Sqlitedatabase getwritabledatabase () {if (Mdatabas E! = null) {if (!mdatabase.isopen ()) {//darn! the user closed the database by calling Mdataba Se.close () mdatabase = null; } else if (!mdatabase.isreadonly ()) {return mdatabase; The database is already open for business}} if (misinitializing) {throw new Ille Galstateexception ("Getwritabledatabase called recursively"); }//If We have a read-only database open, someone could is using it//(though they shouldn ' t), which would Cause a lock to being held on//the file, and we attempts to open the database read-write would//fail wait ing for the file lock. To prevent this, we acquire the//lock on the Read-only database, and which shuts out of 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, Mnewve Rsion); } 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 would be is the same object returned by * {@link #getWritableDatabase} unless some problem, such as a full disk, * requires the database to be opened read-only. In this case, a read-only * database object would be returned. If the problem is fixed, a future call * to {@link #getWritableDatabase} may succeed, in which case the read-only * Database object would be closed and the Read/write object is returned * in the future.* * <p class= "Caution" >like {@link #getWritableDatabase}, this method is * Take a long time to return, so Y OU 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 #getWr Itabledatabase} * 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 Ille Galstateexception ("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 (would 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 (); } }
?? The above analysis can be used to write a custom context class that inherits the context, but it is recommended to use non-abstract classes because there are abstract functions other than the Openorcreatedatabase method in the context Contextwrapper , this class inherits from the context, the custom Databasecontext class source code is as follows:
public class Databasecontext extends Contextwrapper {public Databasecontext (context context) {super (context); /** * Gets the database path, if it does not exist, creates the object object * @param name * @param mode * @param factory */@Over Ride public File Getdatabasepath (String name) {//To determine if there is an SD card boolean sdexist = Android.os.Environment.MEDI A_mounted.equals (Android.os.Environment.getExternalStorageState ()); if (!sdexist) {//If not present, return null; }else{//if present//Get SD card path String dbdir= Fileutils.getflashbpath (); Dbdir + = "DB";//Database directory String DbPath = dbdir+ "/" +name;//database path//Determine if directory exists, does not exist create the directory File Dirfile = new File (dbdir); if (!dirfile.exists ()) {dirfile.mkdirs (); }//Database file is created successfully boolean isfilecreatesuccess = false; Determines whether the file exists, does not exist, and creates the file DBFile = new files (dbPath); if (!dbfile.exists ()){try {isfilecreatesuccess = Dbfile.createnewfile ();//Create File } catch (IOException e) {e.printstacktrace (); }}else{isfilecreatesuccess = true; }//Returns the database file object if (isfilecreatesuccess) {return dbfile; }else{return null; }}}/** * Overloads this method, which is used to open the database on the SD card, Android 2.3 and the following will call this method. * * @param name * @param mode * @param factory */@Override public sqlitedatabase OPENORCR Eatedatabase (String name, int mode, Sqlitedatabase.cursorfactory Factory) {sqlitedatabase result = Sqlitedatabase. Openorcreatedatabase (Getdatabasepath (name), NULL); return result; /** * Android 4.0 calls this method to get the database. * * @see android.content.contextwrapper#openorcreatedatabase (java.lang.String, int, * android.datab Ase.sQlite. Sqlitedatabase.cursorfactory, * android.database.DatabaseErrorHandler) * @param name * @param Mode * @param factory * @param errorhandler * * @Override public sqlitedatabase Openorcreatedat Abase (String name, int mode, Cursorfactory factory, Databaseerrorhandler ErrorHandler) {sqlitedatabase result = SQ Litedatabase.openorcreatedatabase (Getdatabasepath (name), NULL); return result; }}
?? In the constructor of the subclass inheriting Sqliteopenhelper, replace the context with an instance of Databasecontext:
Databasecontext dbContext = new Databasecontext (context); Super (DbContext, mdatabasename, NULL, VERSION);
Description: This article is a great reference to other articles on the web, thanks in particular to the authors of these articles.
Resources:
- Use Sqliteopenhelper to manage databases in an SD card in Android
Android saves the database to an SD card implementation