非余之渔

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

      1、今天在做数据库升级的时候,遇到一个问题,就是onCreate方法和onUpgrade方法的执行时机的问题,这个当时在操作的时候,没有弄清楚,很是迷糊,后来看了相关的博客由于转发受限所以copy了一下,接下来就一起分享一下。

首先我们看看SQLiteOpenHelper类的源码:

它里面有一个重要的方法:getDatabaseLocked

这里我们看到当我们的mName变量为null的时候,就会创建一个内存数据库,数据的生命周期是Application级别的,这个mName就是创建数据库的文件名。

 

当然正常情况下,我们都会传入一个数据库文件名的,所以这个方法一般不会执行的,那么就走下面的代码。下面的代码就是直接打开一个数据库。不过我们看到一个特点,就是创建数据库和Context有关系呢。我们看一下Context中的代码。不过这里我们知道Context是一个抽象类,我们一般会看他的子类ContextImpl实现:

主要看一下getDatabasePath方法和openOrCreateDatabase方法:

首先来看一下openOrCreateDatabase方法:

[java] view plain copy
 
  1. @Override  
  2. public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,  
  3.         DatabaseErrorHandler errorHandler) {  
  4.     File f = validateFilePath(name, true);  
  5.     int flags = SQLiteDatabase.CREATE_IF_NECESSARY;  
  6.     if ((mode & MODE_ENABLE_WRITE_AHEAD_LOGGING) != 0) {  
  7.         flags |= SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING;  
  8.     }  
  9.     SQLiteDatabase db = SQLiteDatabase.openDatabase(f.getPath(), factory, flags, errorHandler);  
  10.     setFilePermissionsFromMode(f.getPath(), mode, 0);  
  11.     return db;  
  12. }  

这里我们看到其实还是调用了SQLiteDatabase的openDatabase方法

 

 

再来看一下getDatabasePath方法:

 

[java] view plain copy
 
  1. @Override  
  2. public File getDatabasePath(String name) {  
  3.     return validateFilePath(name, false);  
  4. }  

 

 

我们看到这两个方法都是有一个核心的方法:validateFilePath

 

[java] view plain copy
 
  1. private File validateFilePath(String name, boolean createDirectory) {  
  2.     File dir;  
  3.     File f;  
  4.   
  5.     if (name.charAt(0) == File.separatorChar) {  
  6.         String dirPath = name.substring(0, name.lastIndexOf(File.separatorChar));  
  7.         dir = new File(dirPath);  
  8.         name = name.substring(name.lastIndexOf(File.separatorChar));  
  9.         f = new File(dir, name);  
  10.     } else {  
  11.         dir = getDatabasesDir();  
  12.         f = makeFilename(dir, name);  
  13.     }  
  14.   
  15.     if (createDirectory && !dir.isDirectory() && dir.mkdir()) {  
  16.         FileUtils.setPermissions(dir.getPath(),  
  17.             FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,  
  18.             -1, -1);  
  19.     }  
  20.   
  21.     return f;  
  22. }  

这个方法其实很简单,就是通过传递过来的数据库名称name,然后构建一个数据库文件File对象返回即可。

 

 

那么上面的几个方法我们可以总结功能:

通过传递过来的数据库名称name,创建一个File对象,然后得到数据库文件的path..传递给SQLDatabase的openDatabase方法中,打开数据库文件

 

下面我们继续来看那个流程:

 

[java] view plain copy
 
  1. final int version = db.getVersion();  
  2. if (version != mNewVersion) {  
  3.     if (db.isReadOnly()) {  
  4.         throw new SQLiteException("Can't upgrade read-only database from version " +  
  5.                 db.getVersion() + " to " + mNewVersion + ": " + mName);  
  6.     }  
  7.   
  8.     db.beginTransaction();  
  9.     try {  
  10.         if (version == 0) {  
  11.             onCreate(db);  
  12.         } else {  
  13.             if (version > mNewVersion) {  
  14.                 onDowngrade(db, version, mNewVersion);  
  15.             } else {  
  16.                 onUpgrade(db, version, mNewVersion);  
  17.             }  
  18.         }  
  19.         db.setVersion(mNewVersion);  
  20.         db.setTransactionSuccessful();  
  21.     } finally {  
  22.         db.endTransaction();  
  23.     }  
  24. }  

当打开数据库文件的时候,我们就开始进行操作了,今天讲的内容最主要的就是上面的判断了:

 

首先获取数据库的当前版本,当版本号为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()方法升级数据库,并更新版本号。

posted on 2016-12-02 15:05  非余之渔  阅读(738)  评论(0编辑  收藏  举报