都知道在Android中SQLiteOpenHelper是用来创建和升级数据库,参考
$ANDROID_SDK_HOME/docs/reference/android/database/sqlite/SQLiteOpenHelper.html

软件发布出去了,用户已经安装使用了,但是随着软件的升级,数据库结构做了些改动,我们不希望用户把应用卸载了再装(这样会丢失应用所有的数据),我们希望在数据库总体结构和已有数据不变的情况下做些小的改动,比如新增一个字段或索引,新增加一个表等等,那么这个时候我们就要用到这个类了

常用的也就是onCreate和onUpgrade这两个方法,在使用的时候这两个方法都需要重写,里面实现自己的逻辑

我们先列出一个场景:
假设第一版程序发布出去,First Public Version,代码如下

1 @Override
2 public void onCreate(SQLiteDatabase db) {
3 bootstrapDB(db);
4 }
5
6 @Override
7 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
8 }

onUpgrade里面没有代码,第一版出去没有需要更新的,bootstrapDB方法就是些DDL和数据初始化操作等等

之后过了一段时间,新的程序发布(其中数据库结构做了些变化),这个时候已经开始使用第一版程序的用户就需要升级,我们不希望他已经存在的数据被破坏,那么我们发布出去的新的版本中代码该怎么写呢?
直接看代码,这些代码都是从Android自带的应用中抽取出来的,做了些具体业务上的简化,主要是阐述清楚用法

1 @Override
2 public void onCreate(SQLiteDatabase db) {
3 bootstrapDB(db); // 这个方法里面都是最新版的初始化方法
4 }
5
6 @Override
7 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
8 Log.i(TAG, "Upgrading DB from version " + oldVersion + " to "
9 + newVersion);
10 if (oldVersion == 1) {
11 upgradeToVersion2(db);
12 oldVersion += 1;
13 }
14 Log.v("do upgrade", "我更新了。。。");
15 }

这样如果后来又有新的程序发布,那么这两个方法会变成类似这个样子

1 @Override
2 public void onCreate(SQLiteDatabase db) {
3 bootstrapDB(db); // 这个方法里面始终都是最新版的初始化方法
4 }
5
6 @Override
7 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
8 Log.i(TAG, "Upgrading DB from version " + oldVersion + " to "
9 + newVersion);
10 if (oldVersion == 1) {
11 upgradeToVersion2(db);
12 oldVersion += 1;
13 }
14 if (oldVersion == 2) {
15 upgradeToVersion3(db);
16 oldVersion += 1;
17 }
18 // 这是一种逐级更新的方式
19 // 对于目前使用的还是第一版的用户而言,会先执行完upgradeToVersion2再执行upgradeToVersion3
20 // 对于目前使用的还是第二版的用户而言,会执行upgradeToVersion3
21 Log.v("do upgrade", "我更新了。。。");
22 }

这样也许就能看的很清楚这个类的意图和用法了,后面版本一直增加的话,我们就一直这样写就好,保证全新的用户和升级的用户都能正常使用,那么我们如何来调用呢
一般我们会有个构造方法,有个参数就是数据库的版本,比如下面这两个构造方法

1 public MyDatabaseHelper(Context context, String name, CursorFactory factory,
2 int version) {
3 super(context, name, factory, version);
4 }
5
6 public MyDatabaseHelper(Context context, int version) {
7 super(context, NAME, null, version);
8 }

采用如下方式调用

1 helper = new MyDatabaseHelper(context, 10); // 这个数据库版本号会随着程序的每次发布而变化,是表示每次需要更新到的版本号,也就是最新的版本号
2 sqlite = helper.getWritableDatabase();

其实更好理解这个用法就是读SQLiteOpenHelper.getWritableDatabase这个方法,里面有段代码

1 int version = db.getVersion();
2 if (version != mNewVersion) {
3 db.beginTransaction();
4 try {
5 if (version == 0) {
6 onCreate(db);
7 } else {
8 onUpgrade(db, version, mNewVersion);
9 }
10 db.setVersion(mNewVersion);
11 db.setTransactionSuccessful();
12 } finally {
13 db.endTransaction();
14 }
15 }

另外,看看set/get Version就知道数据库版本标记是通过PRAGMA user_version;这个命令来完成的,你也可以用sqlite3之类的工具把数据库文件打开,然后执行PRAGMA user_version查看或者设置版本值

如下是完整的两个代码,是目前在使用的

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 package org . xkit . android . demo ; import java.util.ArrayList ; import java.util.HashMap ; import java.util.List ; import java.util.Map ; import android.content.Context ; import android.database.Cursor ; import android.database.sqlite.SQLiteDatabase ; import android.util.Log ; public class DBAdapter { private Context context ; private SQLiteDatabase sqlite ; private MyDatabaseHelper helper ; public DBAdapter ( Context c ) { this . context = c ; } public void open () { helper = new MyDatabaseHelper ( context , 10 ); sqlite = helper . getWritableDatabase (); } public void execSQL ( String sql ) { Log . i ( "sql execute" , sql ); sqlite . execSQL ( sql ); } public Cursor getResultSet ( String tableName , String condition , Object [] fields ) { StringBuffer sb = new StringBuffer (); String allFields = new String (); if ( fields == null ) { allFields = "*" ; } else { for ( int i = 0 ; i < fields . length ; i ++) { allFields += fields [ i ]. toString () + "," ; } allFields = allFields . substring ( 0 , allFields . length () - 1 ); } sb . append ( "select " ). append ( allFields ). append ( " from " ). append ( tableName ). append ( " where " ). append ( condition ); Log . i ( "sqlquery" , sb . toString ()); return sqlite . rawQuery ( sb . toString (), null ); } public Cursor getResultSet ( String sql ) { Log . i ( "sql query" , sql ); return sqlite . rawQuery ( sql , null ); } public List < Map < String , String >> getResultSet ( String sql , int pageSize ) { Log . i ( "sql query" , sql ); Cursor cursor = sqlite . rawQuery ( sql , null ); int count = cursor . getCount (); int columnCount = cursor . getColumnCount (); Log . d ( "Column Count" , "" + columnCount ); List < Map < String , String >> list = new ArrayList < Map < String , String >>( count ); Map < String , String > entity = new HashMap < String , String >( columnCount ); for ( cursor . moveToFirst (); ! cursor . isAfterLast (); cursor . moveToNext ()) { // 找出一共有多少列 for ( int i = 0 ; i < columnCount ; i ++) { Log . d ( "Column Found" , cursor . getColumnName ( i ) + " : " + cursor . getString ( i )); entity . put ( cursor . getColumnName ( i ), cursor . getString ( i )); } list . add ( entity ); } cursor . close (); entity = null ; return list ; } public void close () { // 关闭我们打开的数据库 throw new RuntimeException ( "Only for Stub!" ); } }
view raw DBAdapter.java This Gistbrought to you by GitHub.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778 package org . xkit . android . demo ; import android.content.Context ; import android.database.sqlite.SQLiteDatabase ; import android.database.sqlite.SQLiteOpenHelper ; import android.database.sqlite.SQLiteDatabase.CursorFactory ; import android.util.Log ; public class MyDatabaseHelper extends SQLiteOpenHelper { private static final String TAG = "MyDatabaseHelper" ; public static final String NAME = "lucane.db" ; public MyDatabaseHelper ( Context context , String name , CursorFactory factory , int version ) { super ( context , name , factory , version ); } public MyDatabaseHelper ( Context context , int version ) { super ( context , NAME , null , version ); } @Override public void onCreate ( SQLiteDatabase db ) { bootstrapDB ( db ); } @Override public void onUpgrade ( SQLiteDatabase db , int oldVersion , int newVersion ) { Log . i ( TAG , "Upgrading DB from version " + oldVersion + " to " + newVersion ); if ( oldVersion < 8 ) { // 如果版本太小,就直接删除,然后创建 // 所以bootstrapDB应该是最新的SQL初始化语句 dropTables ( db ); onCreate ( db ); return ; } if ( oldVersion == 8 ) { upgradeToVersion9 ( db ); oldVersion += 1 ; } if ( oldVersion == 9 ) { upgradeToVersion10 ( db ); oldVersion += 1 ; } // 这是一种逐级更新的方式 Log . v ( "do upgrade" , "我更新了。。。" ); } private void bootstrapDB ( SQLiteDatabase db ) { Log . i ( TAG , "Bootstrapping database" ); db . execSQL ( "CREATE TABLE person (personid integer primary key autoincrement,name varchar(20),age integer )" ); } private void dropTables ( SQLiteDatabase db ) { db . execSQL ( "DROP TABLE IF EXISTS person;" ); } // PATCH方法开始 static void upgradeToVersion10 ( SQLiteDatabase db ) { db . execSQL ( "CREATE INDEX idx_person_name_gender ON person (" + "name" + ", " + "gender" + ");" ); } static void upgradeToVersion9 ( SQLiteDatabase db ) { db . execSQL ( "ALTER TABLE " + "person ADD COLUMN gender INTEGER NOT NULL DEFAULT 1;" ); } // PATCH方法结束 }

更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. SDK大全2的读书笔记
  3. 【Android(安卓)Developers Training】 22. 与其他fragment通信
  4. android 源码 来电流程 详解
  5. eclipse开发环境下,如何根据已有代码创建一个 Android(安卓)工程
  6. Android(安卓)Application 和Webview 之间的交互
  7. Android解析json数据的几种方法
  8. android TextView设置中文字体加粗
  9. EventBus的简单用法及介绍

随机推荐

  1. 想抢先体验Android操作系统的魅力吗?那就
  2. Android下添加新的自定义键值和按键处理
  3. Android绘图机制与处理技巧-更新中
  4. Android(安卓)内存管理 &Memory Leak & O
  5. Android(安卓)KitKat 4.4 Wifi移植AP模式
  6. Socket Android手机客户端与PC服务端局域
  7. Android(安卓)M 新的运行时权限开发者需
  8. 学习Android的几大主攻方向
  9. Android原生分享到微博、微信等平台的实
  10. 对Android及移动互联网的大局观看法!