读书人

Context与SQLiteDatabase的步骤openOr

发布时间: 2012-08-30 09:55:54 作者: rapoo

Context与SQLiteDatabase的方法openOrCreateDatabase的区别 (context、SQLiteOpenHelper)

 梳理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();
}
}
}




读书人网 >其他数据库

热点推荐