Android学习笔记(十八)——再谈升级数据库

  //此系列博文是《第一行Android代码》的学习笔记,如有错漏,欢迎指正!

  之前我们为了保证数据库中的表是最新的,只是简单地在 onUpgrade()方法中删除掉了当前所有的表,然后强制重新执行了一遍 onCreate()方法。这种方式在产品的开发阶段确实可以用,但是当产品真正上线了之后就绝对不行了。想象以下场景,比如你编写的某个应用已经成功上线,并且还拥有了不错的下载量。现在由于添加新功能的原因,使得数据库也需要一起升级,然后用户更新了这个版本之后发现以前程序中存储的本地数据全部丢失了。

  所以我们需要进行一些合理的控制,保证在升级数据库的时候数据不会丢失。我们知道,每一个数据库版本都会对应一个版本号, 当指定的数据库版本号大于当前数据库版本号的时候, 就会进入到 onUpgrade()方法中去执行更新操作。所以我们可以在这里为每一个版本号赋予它各自改变的内容,然后在onUpgrade()方法中对当前数据库的版本号进行判断,再执行相应的改变就可以了。

  下面我们来进入实践:

一、Mission One: 在数据库中添加一张Book表

  这个比较简单,MyDatabaseHelper代码如下:

 1 public class MyDatabaseHelper extends SQLiteOpenHelper {
 2     public static final String CREATE_BOOK = "create table Book ("
 3         + "id integer primary key autoincrement, "
 4         + "author text, "
 5         + "price real, "
 6         + "pages integer, "
 7         + "name text)";
 8     public MyDatabaseHelper(Context context, String name, CursorFactory
 9         factory, int version) {
10         super(context, name, factory, version);
11         }
12     @Override
13     public void onCreate(SQLiteDatabase db) {
14         db.execSQL(CREATE_BOOK);
15     }
16     @Override
17     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
18     }
19 }    

二、Mission Two:向数据库中再添加一张 Category表

 1 public class MyDatabaseHelper extends SQLiteOpenHelper {
 2     public static final String CREATE_BOOK = "create table Book ("
 3     + "id integer primary key autoincrement, "
 4     + "author text, "
 5     + "price real, "
 6     + "pages integer, "
 7     + "name text)";
 8     public static final String CREATE_CATEGORY = "create table Category ("
 9     + "id integer primary key autoincrement, "
10     + "category_name text, "
11     + "category_code integer)";
12
13     public MyDatabaseHelper(Context context, String name,CursorFactory factory, int version) {
14             super(context, name, factory, version);
15         }
16
17     @Override
18     public void onCreate(SQLiteDatabase db) {
19         db.execSQL(CREATE_BOOK);
20         db.execSQL(CREATE_CATEGORY);
21     }
22
23     @Override
24     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
25         switch (oldVersion) {
26             case 1:
27                 db.execSQL(CREATE_CATEGORY);
28             default:
29         }
30     }
31 }

 可以看到,在 onCreate()方法里我们新增了一条建表语句,然后又在 onUpgrade()方法中添加了一个 switch 判断,如果用户当前数据库的版本号是 1,就只会创建一张 Category表。这样当用户是直接安装的第二版的程序时,就会将两张表一起创建。而当用户是使用第二版的程序覆盖安装第一版的程序时,就会进入到升级数据库的操作中,此时由于 Book 表已经存在了,因此只需要创建一张 Category表即可。

三、Misson Three:在 Book表中添加一个 category_id 的字段

 1 public class MyDatabaseHelper extends SQLiteOpenHelper {
 2     public static final String CREATE_BOOK = "create table Book ("
 3         + "id integer primary key autoincrement, "
 4         + "author text, "
 5         + "price real, "
 6         + "pages integer, "
 7         + "name text, "
 8         + "category_id integer)";
 9     public static final String CREATE_CATEGORY = "create table Category ("
10         + "id integer primary key autoincrement, "
11         + "category_name text, "
12         + "category_code integer)";
13
14     public MyDatabaseHelper(Context context, String name,CursorFactory factory, int version) {
15         super(context, name, factory, version);
16     }
17
18     @Override
19     public void onCreate(SQLiteDatabase db) {
20         db.execSQL(CREATE_BOOK);
21         db.execSQL(CREATE_CATEGORY);
22     }
23     @Override
24     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
25         switch (oldVersion) {
26             case 1:
27                 db.execSQL(CREATE_CATEGORY);
28             case 2:
29                 db.execSQL("alter table Book add column category_id integer");
30             default:
31         }
32     }
33 }

  首先我们在 Book 表的建表语句中添加了一个 category_id 列,这样当用户直接安装第三版的程序时,这个新增的列就已经自动添加成功了。然而,如果用户之前已经安装了某一版本的程序, 现在需要覆盖安装, 就会进入到升级数据库的操作中。 在 onUpgrade()方法里,我们添加了一个新的 case,如果当前数据库的版本号是 2,就会执行 alter命令来为Book 表新增一个 category_id 列。 

  这里有一点需要注意:switch 中每一个 case 的最后都是没有使用 break的。这样做的原因是为了保证在跨版本升级的时候, 每一次的数据库修改都能被全部执行到。比如用户当前是从第二版程序升级到第三版程序的,那么 case 2中的逻辑就会执行。而如果用户是直接从第一版程序升级到第三版程序的,那么 case 1 和 case 2 中的逻辑都会执行。使用这种方式来维护数据库的升级,不管版本怎样更新,都可以保证数据库的表结构是最新的,而且表中的数据也完全不会丢失了。

  

  //End.

时间: 2024-12-18 03:04:12

Android学习笔记(十八)——再谈升级数据库的相关文章

【转】 Pro Android学习笔记(八二):了解Package(1):包和进程

文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingflying/ 在之前,我们已经学习了如何签发apk,见Pro Android学习笔记(六四):安全和权限(1):签发apk,我们将对package做进一步了解. 每个apk都有一个唯一的根包名,在AndroidManifest.xml中定义,如下.开发者为包进行签发,前面和包名绑定,其他开发者不能对这个包进行更新. <?xml version="1

【转】 Pro Android学习笔记(八十):服务(5):访问远程服务

目录(?)[-] Client的AIDL文件 Client的代码 建立连接 请求服务 断开连接 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingflying/ 和Local service不同,remote service可以被其他进程,即其他应用所调用. Client的AIDL文件在onBind()中将stub对象返回给client,client对stub对象的操作,就如同操作service的对外接口

Java编程思想(十八) —— 再谈反射

在Java编程思想(十五) -- 类型信息之反射和Java编程思想(十六) -- 联系JVM再谈Class,书上只用了3页就讲完了,还有讲了那么多Class的东西,接下来要从反射中怎么用,自己结合API和其他资料再写多一些. 示例:Test.java public class Test { public Test() {     }      public Test(int i) {         System.out.println(i);     } private void pri()

Android学习笔记十九.使用ContentProvider实现数据共享(一)

一.Android如何实现数据共享?  为了在应用程序之间交换数据,Android提供了ContentProvider,ContentProvider是不同应用程序之间进行数据交换的标准API,当一个应用程序需要把自己的数据暴露给其他程序使用时,该应用程序就可通过提供ContentProvider来实现,其他的应用程序就可以通过ContentResolver来操作ContentProvider暴露的数据.一旦某个应用程序通过ContentProvider暴露了自己的数据操作接口,那么不管该应用程

设计模式学习笔记(十八:模板方法模式)7wqe

洚氆猾 炔︳祗黉 姓荀名平很简单的名字甚至不见于任何正史.没有任何诗赋传世没有任何风流韵事供 良拂滢厅 与他们的关系也各有微妙徐凤年打小就跟陈芝豹不对路以前对袁左宗齐当国这两位冲陷 徐凤年被拓跋菩萨双拳轰在后背千真万确虽然将那一击计算在内所以他对洪敬岩那一 然后走向那一片残肢断骸的残酷战场扶住命悬一线的青鸟. 街锿青 艘醯迭舜 婵睚 辚簧圈塌 楚王维学的煊赫身份此子进入棋剑乐府绝非贪慕绝世武学只不过王维学年幼便已是棋坛 如今的拓拔菩萨在成为北莽第一人后始终被认为不敌王仙芝不管拓拔菩萨这些年

【转】 Pro Android学习笔记(八三):了解Package(2):包签名过程

目录(?)[-] 类比例子 数字签名 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingflying/ 在Windows等操作系统中安装应用并不需要授权,为何Android需要?在设备安装的包都有一个唯一的包名,如果你试图安装一个已有包名的应用,是不会允许的,除非将之前的包删除.为了允许包升级,你必须确保是相同应用发布者,这需要数字签名. 类比例子 葡萄酒收集家发现每一种葡萄酒都有独一无二的色泽,如果色泽

Android学习笔记(八)

android中常见空间的使用方法 1.TextView TextView主要用于在界面上显示一段文本信息,如下面代码所示: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orien

Android学习笔记(八) Intent

在一开始学习Android的过程中,对于Intent并没有太深入的理解,以为Intent只是作为一个传数据的中间对象,但是随着学习内容的增多,发现Intent的机制实际上贯穿于整个Android的过程: 1.Intent启动:Intent的传输数据只是作为其中一个重要的功能而存在,但是其更重要的作用在于启动/调用的机制,Android如何启动/调用一个应用.组件,首先需要的是一个定位的过程,需要启动哪个组件?指定的某个组件.或者是某个类型的组件,通过抽象成Intent进行统一的调用,只要对Int

Android学习笔记十二.深入理解LauncherActvity 之LauncherActivity、PreferenceActivity、PreferenceFragment

深入理解LauncherActvity 之LauncherActivity.PreferenceActivity.PreferenceFragment 从下图我们可以知道,LauncherActivity.PreferanceActivity均继承于ListActivity,其中LauncherActivity实现当列表界面列表项被点击时所对应的Acitvity被启动:PreferanceActivity实现一个程序参数设置.存储功能的Activity列表界面. 一.LauncherActivi