今天在作数据库升级的时候,遇到一个问题,就是onCreate方法和onUpgrade方法的执行时机的问题,这个当时在操做的时候,没有弄清楚,非常迷糊,因此写代码的时候出现了不少的问题,因此没办法就去扒源代码看了。不过在此以前我讲解过一篇关于数据库升级的文章,可是那里没有详细的讲解一下这两个方法的执行时机,因此这里就在单独说一下java
关于数据库升级的文章:http://blog.csdn.net/jiangwei0910410003/article/details/39670813数据库
很少说,下面直接进入主题吧:ide
首先咱们看看SQLiteOpenHelper类的源码:spa
它里面有一个重要的方法:getDatabaseLocked.net
这里咱们看到当咱们的mName变量为null的时候,就会建立一个内存数据库,数据的生命周期是Application级别的,这个mName就是建立数据库的文件名。code
固然正常状况下,咱们都会传入一个数据库文件名的,因此这个方法通常不会执行的,那么就走下面的代码。下面的代码就是直接打开一个数据库。不过咱们看到一个特色,就是建立数据库和Context有关系呢。咱们看一下Context中的代码。不过这里咱们知道Context是一个抽象类,咱们通常会看他的子类ContextImpl实现:对象
主要看一下getDatabasePath方法和openOrCreateDatabase方法:blog
首先来看一下openOrCreateDatabase方法:生命周期
@Override 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; }这里咱们看到其实仍是调用了SQLiteDatabase的openDatabase方法
再来看一下getDatabasePath方法:内存
@Override public File getDatabasePath(String name) { return validateFilePath(name, false); }
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; }这个方法其实很简单,就是经过传递过来的数据库名称name,而后构建一个数据库文件File对象返回便可。
那么上面的几个方法咱们能够总结功能:
经过传递过来的数据库名称name,建立一个File对象,而后获得数据库文件的path..传递给SQLDatabase的openDatabase方法中,打开数据库文件
下面咱们继续来看那个流程:
final int version = db.getVersion(); if (version != mNewVersion) { if (db.isReadOnly()) { throw new SQLiteException("Can't upgrade read-only database from version " + db.getVersion() + " to " + mNewVersion + ": " + mName); } db.beginTransaction(); try { if (version == 0) { onCreate(db); } else { if (version > mNewVersion) { onDowngrade(db, version, mNewVersion); } else { onUpgrade(db, version, mNewVersion); } } db.setVersion(mNewVersion); db.setTransactionSuccessful(); } finally { db.endTransaction(); } }当打开数据库文件的时候,咱们就开始进行操做了,今天讲的内容最主要的就是上面的判断了:
首先获取数据库的当前版本,当版本号为0的时候,就会执行onCreate方法(当数据库文件第一次建立的时候版本号就是0)若是版本号不为0,同时和最新版本号进行比较,若是大于的话,就执行升级操做onUpgrade方法,不然就执行降级onDowngrade方法,不过降级方法实现很简单:
直接抛出异常,也就是说数据库不容许降级操做的,这个也符合正常状况。
好了。经过上面的分析,下面咱们就对这两个方法作一下总结:
public abstract void onCreate(SQLiteDatabase db);
public abstract void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion);
SQLiteOpenHelper会自动检测数据库文件是否存在。若是存在,会打开这个数据库,在这种状况下就不会调用onCreate()方法。若是数据库文件不存在,SQLiteOpenHelper首先会建立一个数据库文件,而后打开这个数据库,最后调用onCreate()方法。所以,onCreate()方法通常用来在新建立的数据库中创建表、视图等数据库组建。
也就是说onCreate()方法在数据库文件第一次建立时调用。
先看看SQLiteOpenHelper类的构造方法再解释onUpdate()方法什么时候会被调用。
public SQLiteOpenHelper(Context context,String name,CursorFactory factory,int version);
其中name参数表示数据库文件名(不包括文件路径),SQLiteOpenHelper会根据这个文件名建立数据库文件。version表示数据库的版本号。若是当前传入的数据库版本号比上次建立或升级的版本号高,SQLiteOpenHelper就会调用onUpdate()方法。也就是说,当数据库第一次建立时会有一个初始的版本号。当须要对数据库中的表、视图等组建升级时能够增大版本号,再从新建立它们。如今总结一下onCreate()和onUpgrade()调用过程。
1.若是数据库文件不存在,SQLiteOpenHelper在自动建立数据库后会调用onCreate()方法,在该方法中通常须要建立表、视图等组件。在建立前数据库通常是空的,所以不须要先删除数据库中相关的组件。
2.若是数据库文件存在,而且当前版本号高于上次建立或升级的版本号,SQLiteOpenHelper会调用onUpgrade()方法,调用该方法后会更新数据库的版本号。在onUpgrade()方法中除了建立表、视图等组件外,还须要先删除这些相关的组件,所以,在调用onUpgrade()方法前,数据库是存在的,里面还原许多数据库组建。
综合上述两点,能够得出一个结论:
若是数据库文件不存在,只有onCreate()被调用(该方法在建立数据库时被调用一次)。若是数据库文件存在,会调用onUpgrade()方法升级数据库,并更新版本号。