我们知道,android开发时少不了用到数据库,android系统提供了轻量级的数据库:SQLite。在你的应用开发中,如果需要用到数据库就能使用SQLite了。为了使用的SQLite方便,Android提供了SQLite的一个工具类:SQLiteOpenHelper。如果能够保证更好的用SQLite,你当然你可以不用这个工具类。这里我们来看看SQLiteOpenHelper的实现。
(1)首先,SQLiteOpenHelper是一个abstract的类,所以,你不能直接用这个工具类,必须以该类为父类写一个自己的工具类来操作自己需要的数据库。这里我们先后介绍两个我们常用的两个abstract 方法:
/**
* Called when the database is created for the first time. This is where the
* creation of tables and the initial population of the tables should happen.
*
* @param db The database.
*/
public abstract void onCreate(SQLiteDatabase db);
从这个方法的原文说明可以知道:onCreate 这个方法是在database第一次创建时候调用的,一般用来为这个数据库创建我们需要用到的表以及这些表的一些初始化工作。所以,很显然,调用这个方法时候,这个数据库文件肯定已经创建好了。一般情况下,这个方法是我们必须要用到的。
/**
* Called when the database needs to be upgraded. The implementation
* should use this method to drop tables, add tables, or do anything else it
* needs to upgrade to the new schema version.
*
* <p>
* The SQLite ALTER TABLE documentation can be found
* <a href="http://sqlite.org/lang_altertable.html">here</a>. If you add new columns
* you can use ALTER TABLE to insert them into a live table. If you rename or remove columns
* you can use ALTER TABLE to rename the old table, then create the new table and then
* populate the new table with the contents of the old table.
* </p><p>
* </p><p>
* This method executes within a transaction. If an exception is thrown, all changes
* will automatically be rolled back.
* </p>
*
* @param db The database.
* @param oldVersion The old database version.
* @param newVersion The new database version.
*/
public abstract void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);
从上面的英文说明可以知道onUpgrade这个方法主要是用于更新、更改数据库的,一般主要用于该数据库中表的修改。比如需要删除一些表、添加一些表、修改表中某一项等。
(2)来看看database是如何创建的:
首先来看看他的构造方法:
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
DatabaseErrorHandler errorHandler) {
if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
mContext = context;
mName = name;
mFactory = factory;
mNewVersion = version;
mErrorHandler = errorHandler;
}
从这个方法可以看出,其实这个方法没有创建database,只是做了一些信息的保存! 那database是如何创建的呢?
首先,来看看下面两个常用的方法:
public SQLiteDatabase getReadableDatabase() {
synchronized (this) {
return getDatabaseLocked(false);
}
}
public SQLiteDatabase getWritableDatabase() {
synchronized (this) {
return getDatabaseLocked(true);
}
}
这两个方法都调用的一个方法:getDatabaseLocked(),很明显这个函数就会返回一个SQLiteDatabase。这个方法代码量太大,我就不一起贴出来了,其实SQLiteOpenHelper的主要工作就这这个方法里面。这个方法主要是获取这个SQLiteDatabase,如果当前还没有这个SQLiteDatabase实例,就会创建一个新的,此外还同时会检测这个SQLiteDatabase实例的版本号和当前这个SQLiteOpenHelper所设置的版本号是否相等,否则就会做相应的升级(调用onUpgrade、onDowngrade来实现)。
这里我们只贴出这个方法里面创建数据库的几行代码:
if (DEBUG_STRICT_READONLY && !writable) {
final String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
} else {
db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
mFactory, mErrorHandler);
}
这里我们关注的是mContext,其实创建一数据库最后是来自这mContext的。这里的mContext的两个方法getDatabasePath和openOrCreateDatabase其实都是可能会创建一个数据库文件的,我们来看看mContext中两个方法:
@Override
public File getDatabasePath(String name) {
return validateFilePath(name, false);
}
public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,
DatabaseErrorHandler errorHandler) {
File f = validateFilePath(name, true);
int flags = SQLiteDatabase.CREATE_IF_NECESSARY;
if ((mode & MODE_ENABLE_WRITE_AHEAD_LOGGING) != 0) {
flags |= SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING;
}
SQLiteDatabase db = SQLiteDatabase.openDatabase(f.getPath(), factory, flags, errorHandler);
setFilePermissionsFromMode(f.getPath(), mode, 0);
return db;
}
看到了吗?其实都会调用一个函数validateFilePath();
private File validateFilePath(String name, boolean createDirectory) {
File dir;
File f;
if (name.charAt(0) == File.separatorChar) {
String dirPath = name.substring(0, name.lastIndexOf(File.separatorChar));
dir = new File(dirPath);
name = name.substring(name.lastIndexOf(File.separatorChar));
f = new File(dir, name);
} else {
dir = getDatabasesDir();
f = makeFilename(dir, name);
}
if (createDirectory && !dir.isDirectory() && dir.mkdir()) {
FileUtils.setPermissions(dir.getPath(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
-1, -1);
}
return f;
}
看到了吗?其实就是创建一个数据库文件new File(base, name)、new File(dirPath)。
(3)我们的关注点来到了Context,在Context里面还有几个方法:
@Override
public boolean deleteDatabase(String name) {
try {
File f = validateFilePath(name, false);
return SQLiteDatabase.deleteDatabase(f);
} catch (Exception e) {
}
return false;
}
@Override
public File getDatabasePath(String name) {
return validateFilePath(name, false);
}
从上面分析可以知道在android中,实际上数据库SQLite的起源是Context ,其实也只是创建数据库、删除数据库、已经获取数据库文件路径等。而android提供的工具SQLiteOpenHelper只是方便我们使用! 我们知道Context 其实是app的activity、service的起源,所以一个数据库实例其实是属于一个APP的,也是这个APP管理的。