都知道在Android中SQLiteOpenHelper是用来创建和升级数据库,参考
$ANDROID_SDK_HOME/docs/reference/android/database/sqlite/SQLiteOpenHelper.html
软件发布出去了,用户已经安装使用了,但是随着软件的升级,数据库结构做了些改动,我们不希望用户把应用卸载了再装(这样会丢失应用所有的数据),我们希望在数据库总体结构和已有数据不变的情况下做些小的改动,比如新增一个字段或索引,新增加一个表等等,那么这个时候我们就要用到这个类了
常用的也就是onCreate和onUpgrade这两个方法,在使用的时候这两个方法都需要重写,里面实现自己的逻辑
我们先列出一个场景:
假设第一版程序发布出去,First Public Version,代码如下
2 | public void onCreate(SQLiteDatabase db) { |
7 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { |
onUpgrade里面没有代码,第一版出去没有需要更新的,bootstrapDB方法就是些DDL和数据初始化操作等等
之后过了一段时间,新的程序发布(其中数据库结构做了些变化),这个时候已经开始使用第一版程序的用户就需要升级,我们不希望他已经存在的数据被破坏,那么我们发布出去的新的版本中代码该怎么写呢?
直接看代码,这些代码都是从Android自带的应用中抽取出来的,做了些具体业务上的简化,主要是阐述清楚用法
2 | public void onCreate(SQLiteDatabase db) { |
7 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { |
8 |
Log.i(TAG, "Upgrading DB from version " + oldVersion + " to " |
10 |
if (oldVersion == 1 ) { |
11 |
upgradeToVersion2(db); |
14 |
Log.v( "do upgrade" , "我更新了。。。" ); |
这样如果后来又有新的程序发布,那么这两个方法会变成类似这个样子
2 | public void onCreate(SQLiteDatabase db) { |
7 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { |
8 |
Log.i(TAG, "Upgrading DB from version " + oldVersion + " to " |
10 |
if (oldVersion == 1 ) { |
11 |
upgradeToVersion2(db); |
14 |
if (oldVersion == 2 ) { |
15 |
upgradeToVersion3(db); |
21 |
Log.v( "do upgrade" , "我更新了。。。" ); |
这样也许就能看的很清楚这个类的意图和用法了,后面版本一直增加的话,我们就一直这样写就好,保证全新的用户和升级的用户都能正常使用,那么我们如何来调用呢
一般我们会有个构造方法,有个参数就是数据库的版本,比如下面这两个构造方法
1 | public MyDatabaseHelper(Context context, String name, CursorFactory factory, |
3 |
super (context, name, factory, version); |
6 | public MyDatabaseHelper(Context context, int version) { |
7 |
super (context, NAME, null , version); |
采用如下方式调用
1 | helper = new MyDatabaseHelper(context, 10 ); |
2 | sqlite = helper.getWritableDatabase(); |
其实更好理解这个用法就是读SQLiteOpenHelper.getWritableDatabase这个方法,里面有段代码
1 | int version = db.getVersion(); |
2 | if (version != mNewVersion) { |
8 |
onUpgrade(db, version, mNewVersion); |
10 |
db.setVersion(mNewVersion); |
11 |
db.setTransactionSuccessful(); |
另外,看看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方法结束 } |
- SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
- SDK大全2的读书笔记
- 【Android(安卓)Developers Training】 22. 与其他fragment通信
- android 源码 来电流程 详解
- eclipse开发环境下,如何根据已有代码创建一个 Android(安卓)工程
- Android(安卓)Application 和Webview 之间的交互
- Android解析json数据的几种方法
- android TextView设置中文字体加粗
- EventBus的简单用法及介绍
随机推荐
-
想抢先体验Android操作系统的魅力吗?那就
-
Android下添加新的自定义键值和按键处理
-
Android绘图机制与处理技巧-更新中
-
Android(安卓)内存管理 &Memory Leak & O
-
Android(安卓)KitKat 4.4 Wifi移植AP模式
-
Socket Android手机客户端与PC服务端局域
-
Android(安卓)M 新的运行时权限开发者需
-
学习Android的几大主攻方向
-
Android原生分享到微博、微信等平台的实
-
对Android及移动互联网的大局观看法!