[android] 01_SQLiteOpenHelper介绍

Android 4.0


一、SQLiteOpenHelper 的简单介绍

我们在编写数据库应用软件时,需要考虑这样的问题:因为我们开发的软件可能会安装在很多用户的手机上,如果应用使用到了SQLite数据库,我们必须在用户初次使用软件时创建出应用使用到的数据库表结构及添加一些初始化记录,另外在软件升级的时候,也需要对数据表结构进行更新。那么,我们如何才能实现在用户初次使用或升级软件时自动在用户的手机上创建出应用需要的数据库表呢?总不能让我们在每个需要安装此软件的手机上通过手工方式创建数据库表吧?因为这种需求是每个数据库应用都要面临的,所以在Android系统,为我们提供了一个名为SQLiteOpenHelper的抽象类,必须继承它才能使用,它是通过对数据库版本进行管理来实现前面提出的需求。
 
 
为了实现对数据库版本进行管理,SQLiteOpenHelper类提供了两个重要的方法,分别是onCreate(SQLiteDatabase db)onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion),前者用于初次使用软件时生成数据库表,后者用于升级软件时更新数据库表结构。当调用SQLiteOpenHelpergetWritableDatabase()或者getReadableDatabase()方法获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,在onCreate()方法里可以生成数据库表结构及添加一些应用使用到的初始化数据onUpgrade()方法在数据库的版本发生变化时会被调用,一般在软件升级时才需改变版本,而数据库的版本是由程序员控制的,假设数据库现在的版本是1,由于业务的变更,修改了数据库表结构,这时候就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2(有同学问设置为3行不行?当然可以,如果你愿意,设置为100也行),并且在onUpgrade()方法里面实现表结构的更新。当软件的版本升级次数比较多,这时在onUpgrade()方法里面可以根据原版号和目标版本号进行判断,然后作出相应的表结构及数据更新。
 
 
getWritableDatabase()getReadableDatabase()方法都可以获取一个用于操作数据库的SQLiteDatabase实例。但getWritableDatabase() 方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用getWritableDatabase()打开数据库就会出错。getReadableDatabase()方法先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。

二、使用SQLiteOpenHelper对数据库进行版本管理

public class DatabaseHelper extends SQLiteOpenHelper {
    //类没有实例化,是不能用作父类构造器的参数,必须声明为静态
     private static final String name = "itcast"; //数据库名称
     private static final int version = 1; //数据库版本
     public DatabaseHelper(Context context) {
    //第三个参数CursorFactory指定在执行查询时获得一个游标实例的工厂类,设置为null,代表使用系统默认的工厂类
        super(context, name, null, version);
     }
    @Override public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE IF NOT EXISTS person (personid integer primary key autoincrement, name varchar(20), age INTEGER)");   
     }
    @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL(" ALTER TABLE person ADD phone VARCHAR(12) NULL "); //往表中增加一列
        // DROP TABLE IF EXISTS person 删除表
   }
}
//在实际项目开发中,当数据库表结构发生更新时,应该避免用户存放于数据库中的数据丢失。

 

三、使用SQLiteOpenHelper获取用于操作数据库的SQLiteDatabase实例

public class DatabaseHelper extends SQLiteOpenHelper {
         private static final String name = "itcast"; //数据库名称
         private static final int version = 1; //数据库版本
         ......
}
public class HelloActivity extends Activity {
    @Override public void onCreate(Bundle savedInstanceState) {
        ......
        Button button =(Button) this.findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener(){
        public void onClick(View v) {
                    DatabaseHelper databaseHelper = new DatabaseHelper(HelloActivity.this);
                    SQLiteDatabase db = databaseHelper.getWritableDatabase();
                    db.execSQL("insert into person(name, age) values(?,?)", new Object[]{"传智播客", 4});            db.close(); 
        }});       
    }
}
第一次调用getWritableDatabase()getReadableDatabase()方法后,SQLiteOpenHelper会缓存当前的SQLiteDatabase实例,SQLiteDatabase实例正常情况下会维持数据库的打开状态,所以在你不再需要SQLiteDatabase实例时,请及时调用close()方法释放资源。一旦SQLiteDatabase实例被缓存,多次调用getWritableDatabase()getReadableDatabase()方法得到的都是同一实例。

1、SQLiteOpenHelper

import android.content.Context;

import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class PersonDBOpenHelper extends SQLiteOpenHelper {
 
    private static final String TAG = "PersonDBOpenHelper";
    /**
     * @param context
     *            上下文 to use to open or create the database
     * @param name
     *            如果为null,表示为一个内存数据库(断电后数据会丢失),如果指定了一个名字,那就是数据库名 of the database file, or null for an in-memory database
     * @param factory
     *            数据库查询结果的游标工厂,为null,表示用默认的工厂创建Cursor
     * @param version
     *            数据库的版本 >=1
     */
    public PersonDBOpenHelper(Context context, String name,
            CursorFactory factory, int version) {
        super(context, name, factory, version);
    }
    /**
     * 数据库在<b> 第一次</b> 创建的时候调用的方法 Called when the database is created for the
     * first time 适合做数据库表结构的初始化
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.i(TAG"PersonDBOpenHelper  onCreate运行了。。。");
        db.execSQL("create table person (id integer primary key autoincrement,  name varchar(20), phone varchar(20))");
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.i(TAG"PersonDBOpenHelper onUpgrade() 运行了。。。。");
        // 程序1.0的版本已经发布了.
        // 程序的2.0的版本也要发布了. 2.0的版本 增加一个新的表
    }

}

测试类:

public class TestPersonDBOpenHelper extends AndroidTestCase {
    public void test() {
        // getContext() 获取的是一个假的模拟的上下文 一个方便测试框架使用的上下文
        PersonDBOpenHelper helper = new PersonDBOpenHelper(getContext(), "mydb.db"null,2);//不会创建数据库
        SQLiteDatabase database = helper.getWritableDatabase();// 创建或者获取一个可读写的数据库
        database.close();
    }
}
SQLiteOpenHelper小结:
 
1、构造方法public SQLiteOpenHelper(Context context, String name,CursorFactory factory, int version)
a) 上下文 to use to open or create the database
b) 如果为null,表示为一个内存数据库(断电后数据会丢失),如果指定了一个名字(文件数据库),
   即是数据库名。of the database file, or null for an in-memory database
c) 数据库查询结果的游标工厂,为null,表示用默认的工厂创建Cursor
d) 数据库的版本 >=1
 
2、方法:
onCreate(SQLiteDatabase db)    适合做数据库表结构的初始化
   数据库在第一次创建的时候调用的方法 Called when the database is created for the first time 
onUpgrade(SQLiteDatabase dbint oldVersion, int newVersion) 数据库更新后调用
// 程序1.0的版本已经发布了.
// 程序的2.0的版本也要发布了. 2.0的版本 增加一个新的表
 
3、PersonDBOpenHelper helper = new PersonDBOpenHelper(getContext(), "mydb.db"null,2);
   //并不会创建数据库
SQLiteDatabase database = helper.getWritableDatabase();// 创建或者获取一个可读写的数据库
 
4、测试框架中getContext(),获取的是一个假的模拟的上下文 一个方便测试框架使用的上下文

2、创建的数据库的在手机上的位置

可以使用SQLite_Expert_Professional将导出的mydb.db数据库文件查看。

http://www.sqliteexpert.com/download.html