梳理SQLiteDatabase、openOrCreateDatabase、SQLiteOpenHelper
据我所知,android创建数据库可以通过以下方法:
一、 SQLiteDatabase.openOrCreateDatabase(file, factory):(以下都在这个SQLiteDatabase类中)
1. 一个类名+方法就是个static方法:
public static SQLiteDatabase openOrCreateDatabase(File file, CursorFactory factory) {
return openOrCreateDatabase(file.getPath(), factory);
}
2. 换了绝对路径。
public static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory) {
return openDatabase(path, factory, CREATE_IF_NECESSARY);
}
3.去调用了openDatabase方法。
public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
SQLiteDatabase db = null;
try {
// Open the database.
return new SQLiteDatabase(path, factory, flags);
} catch (SQLiteDatabaseCorruptException e) {
// Try to recover from this, if we can.
// TODO: should we do this for other open failures?
Log.e(TAG, "Deleting and re-creating corrupt database " + path, e);
EventLog.writeEvent(EVENT_DB_CORRUPT, path);
new File(path).delete();
return new SQLiteDatabase(path, factory, flags);
}
}
4. 关键的就这行代码:return new SQLiteDatabase(path, factory, flags);其他的是异常处理。
也就是新建了这个类,我们创建数据库也可以这样直接new出来。
5.现在关键的工作就落在SQLiteDatabase这个类的构造函数上了。
private SQLiteDatabase(String path, CursorFactory factory, int flags) {
if (path == null) {
throw new IllegalArgumentException("path should not be null");
}
mFlags = flags;
mPath = path;
mLogStats = "1".equals(android.os.SystemProperties.get("db.logstats"));
mSlowQueryThreshold = SystemProperties.getInt(LOG_SLOW_QUERIES_PROPERTY, -1);
mLeakedException = new IllegalStateException(path +
" SQLiteDatabase created and never closed");
mFactory = factory;
dbopen(mPath, mFlags); <-----------------------------------------------------------
mPrograms = new WeakHashMap<SQLiteClosable,Object>();
try {
setLocale(Locale.getDefault());
} catch (RuntimeException e) {
Log.e(TAG, "Failed to setLocale() when constructing, closing the database", e);
dbclose();
throw e;
}
}
6.起关键的就是 dbopen(mPath, mFlags);
private native void dbopen(String path, int flags);
7.看到这个native,就是jni咯!往下就是c++了。其中细体什么实现open或create就不用管了。感兴趣可以往下跟。
二、context.openOrCreateDatabase(name, mode, factory);
1、看android帮助是这样描述的:
Open a new private SQLiteDatabase associated with this Context's application package.
Create the database file if it doesn't exist.
2 、看源码没发现细体的实现部分的代码,发现的话分享一下给我。搜了很多源码,只有这样:
context.java中:
public abstract SQLiteDatabase openOrCreateDatabase(String name,int mode, CursorFactory factory);
是个抽象方法,其子类ContextWrapper.java:
public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {
return mBase.openOrCreateDatabase(name, mode, factory);
}
又没见哪个子类去覆盖这个方法;
小结:查网上一些资料也是说第二种通过context的方法,其实最终也是得通过SQLiteDatabase这个类中的方法。
我认为也是,因为1.context中也用到SQLiteDatabase 这个类啊,可以直接调用这个SQLiteDatabase 的方法嘛。
2.我们知道在data/data+加上这个应用的包名,就是这个应用程序存放私有数据的目录。那么这个应用程序
只要通过数据库名称就能找到其路径。而这个SQLiteDatabase的 openOrCreateDatabase(File file, CursorFactory factory)
再到openOrCreateDatabase(String path, CursorFactory factory);由此可猜这个openOrCreateDatabase(file...)应该是提供
给context的。
(三) 剩下就是这个SQLiteOpenHelper
1. 都说这个SQLiteOpenHelper.java类是方便操作数据库的类。
2. 那分析一下源码
public abstract class SQLiteOpenHelper
3.所以通常我们要使用个类就得去继承它。并去实现父类的抽象方法如:
public class DatabaseHelper extends SQLiteOpenHelper
{
public DatabaseHelper(Context context, String name, CursorFactory cursorFactory, int version)
{
super(context, name, cursorFactory, version);
}
@Override
public void onCreate(SQLiteDatabase db)
{
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
}
@Override
public void onOpen(SQLiteDatabase db)
{
super.onOpen(db);
}
}
4. 好像就这么简单,其实什么也没做。那什么创建或打开数据库?
5.重要的是SQLiteOpenHelper中的getWritableDatabase和getReadableDatabase方法,你会发现getReadableDatabase中调用了getWritableDatabase
6.所以只要getWritableDatabase清楚getWritableDatabase是如何实现的,就很明朗了。
看似复杂, 慢慢往下看,还有注释(同时要清楚这方法目的就是要创建或打开数据库)
public synchronized SQLiteDatabase getWritableDatabase() {
if (mDatabase != null && mDatabase.isOpen() && !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); //关键是这行代码,是不是很熟悉
}
int version = db.getVersion();
if (version != mNewVersion) {
db.beginTransaction();
try {
if (version == 0) {
onCreate(db); //子类我们实现的方法(其实什么也没做,要想这第一次创建时做一些操作,
//就自己在子类的方法实现,如创建表)
} 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();
}
}
}