Context.openOrCreateDatabase 与 SQLiteDatabase.openOrCreateDatabase本质上完成的功能都一样,Context.openOrCreateDatabase最终是需要调用 SQLiteDatabase.openOrCreateDatabase来完成数据库的创建的。
也就是说, SQLiteDatabase类是android上对sqlite的最底层的封装,几乎所有的对数据库的操作最终都通过这个类来实现。而Context里面提供的方法,是用于上下文的时候创建数据库,例如你在某个逻辑里面创建的数据库只是在特定的context里面,对于数据库的权限,交由context来管理,而这个逻辑可能是会提供给不止一个context。
可以在程序上下文中用openOrCreateDatabase方法来创建和打开一个数据库,方法如下:
private static final String DATABASE_NAME = "betty_db”; private static final String DATABASE_TABLE = “betty_table”; private static final String DATABASE_CREATE = “create table “ + DATABASE_TABLE + “ ( _id integer primary key autoincrement,” + “column_one text not null);”; SQLiteDatabase myDatabase; private void createDatabase() { myDatabase = openOrCreateDatabase(DATABASE_NAME, Context.MODE_PRIVATE, null); myDatabase.execSQL(DATABASE_CREATE); }
转--------------------------------------------------------------------------------
梳理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(); } } } }