如何将sqlite数据库文件与apk文件一起发布?
将数据库文件复制到 res目录下的aw目录下.在aw目录下的文件不会被压缩.
如何打开res aw目录下的数据库文件?
当Activity开始创建的时候,将该目录下的文件使用流的形式复制到手机的sd卡中,然后通sqliteDatabase.openOrCreateDatabase 打开任意目录下的数据库文件.
现在使用sqlite:
使用sqlite,无非进行增删改查.
首先,自定义类继承sqliteOpenHelper
覆写其中的onCreate与onUpgrade方法.
其中onCreate方法 第一次创建数据库时调用的方法,一般用于创建数据库与初始化数据库中的数据.
实例代码:(此处将该类设计成单例模式)
public static final String DB_NAME="person"; public static final int VERSION=1; public static final String DB_NAME="person"; public static final int VERSION=1; public static final String CREATE_TABLE="create table if not exists "+DB_NAME+" (" +" _id integer primary key AUTOINCREMENT," +" name varchar(20) unique," +" age integer(3) default 1 check (age between 1 and 150)," +" address varchar(200)" +" )"; //数据库第一次创建时调用 public void onCreate(sqliteDatabase db) { // TODO Auto-generated method stub db.execsql(CREATE_TABLE); } //数据版本更新时调用 public void onUpgrade(sqliteDatabase db,int oldVersion,int newVersion) { String sql="drop table if exists "+DB_NAME; db.execsql(sql); onCreate(db); }
sqlite进行数据库操作,存在两种方法:
一种是调用 db的 execsql 方法,rawQuery方法.
另一种是调用 db的update insert delete query 方法.
现在分别进行演示:
增加:
public void save(Person p){ sqliteDatabase base=db.getWritableDatabase(); try { String sql="insert into person values(null,?,?)"; base.execsql(sql,new Object[]{p.getName(),p.getAge(),p.getAddress()}); } catch (sqlException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ if(base!=null){ base.close(); } } }
删除:
public void delete(Person p){ sqliteDatabase base=db.getWritableDatabase(); try { String sql="delete from person where _id=?"; base.execsql(sql,new Object[]{p.get_id()}); } catch (sqlException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ if(base!=null){ base.close(); } } }
该:
public void update(Person p){ sqliteDatabase base=db.getWritableDatabase(); try { String sql="update person set name=?,age=?,address=? where _id=?"; base.execsql(sql,p.getAddress(),p.get_id()}); } catch (sqlException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ if(base!=null){ base.close(); } } }
查:
public List<Person> query(){ sqliteDatabase base=db.getWritableDatabase(); String sql="select * from person"; Cursor cursor=base.rawQuery(sql,null); List<Person> persons=new ArrayList<Person>(); while(cursor.moveToNext()){ int _id=cursor.getInt(cursor.getColumnIndexOrThrow("_id")); String name=cursor.getString(cursor.getColumnIndexOrThrow("name")); int age=cursor.getInt(cursor.getColumnIndexOrThrow("age")); String address=cursor.getString(cursor.getColumnIndexOrThrow("address")); Person p=new Person(_id,name,age,address); persons.add(p); } return persons; }
调用db系统给定的api进行操作:
增:
public void save(Person p){ sqliteDatabase base=db.getWritableDatabase(); ContentValues values=new ContentValues(); values.put("name",p.getName()); values.put("_id",p.get_id()); values.put("age",p.getAge()); values.put("address",p.getAddress()); base.insert("person","name",values); } //inert 的第二个参数通常被称为钩子列,主要的作用: 当传入的ContentValues 的值恰好为空的时候,base在底层拼接sql语句的时候或会出现 insert into person null values null 的情况,然后就会报错,通过钩子列的使用,当传入的数据为空的时候,sql语句好歹也会变成 insert into person (name) values null 这样就不会报异常了,所以钩子列一般对付数据为空的情况.
删:
public void delete(Person p){ sqliteDatabase base=db.getWritableDatabase(); base.delete("person","_id=?",new String[]{p.get_id()+""}); }
改:
public void update(Person p){ sqliteDatabase base=db.getWritableDatabase(); ContentValues values=new ContentValues(); values.put("name",p.getName()); values.put("age",p.getAddress()); base.update("person",values,new String[]{p.get_id()+""}); }
查:
public List<Person> query(){ sqliteDatabase base=db.getWritableDatabase(); Cursor cursor=base.query("person",null,address); persons.add(p); } return persons; }
此外,对于sqlite,还提供了替换的操作,替换的时候,会先检查数据库中是否已经存在数据,如果存在,则更新数据,如果不存在,则插入数据.而判断是否是同一条数据的依据是设置了unique约束字段的组合是否相同.
public void replace(HeadInfo info){ sqliteDatabase base=hepler.getWritableDatabase(); ContentValues values=new ContentValues(); values.put(HeadInfo.CreateTime,info.getCreate_time()); values.put(HeadInfo.descriPtion,info.getDescription()); values.put(HeadInfo.Id,info.getId()); values.put(HeadInfo.NickName,info.getNickname()); base.replace(HeadInfo.TableName,HeadInfo.NickName,values); }
完成数据的操作类之后,我们要使用listview搭配SimpleCursorAdapter进行数据的展现.
listview进行数据的初始化时,向数据库中查询数据.
然后更新界面.
界面展现/更新的代码:
获取查询结果的游标,作为参数传给简单游标适配器.
listview如果需要重新刷新界面,更新数据展现,都需要重新从数据库中查询数据,获取游标,然后重新定义适配器,listview重新配置适配器:
cursor=util.query_Cursor(); adapter=new SimpleCursorAdapter(MainActivity.this,R.layout.item,cursor,new String[]{"name","age","address"},new int[]{R.id.text_name,R.id.text_age,R.id.text_address}); listview.setAdapter(adapter);
例如点击按钮,添加数据,刷新界面:
if((!TextUtils.isEmpty(name))&&(!TextUtils.isEmpty(age))&&(!TextUtils.isEmpty(address))){ Person p=new Person(); p.setAddress(address); p.setName(name); p.setAge(Integer.parseInt(age)); util.save(p); //更新界面 cursor=util.query_Cursor(); adapter=new SimpleCursorAdapter(MainActivity.this,R.id.text_address}); listview.setAdapter(adapter);
this.listview.setOnItemLongClickListener(new OnItemLongClickListener() { public boolean onItemLongClick(AdapterView<?> parent,View view,int position,long id) { cursor=(Cursor) adapter.getItem(position); int _id=cursor.getInt(cursor.getColumnIndexOrThrow("_id")); String sql="delete from person where _id=?"; sqliteDatabase base=util.getDb().getWritableDatabase(); base.execsql(sql,new Object[]{_id}); cursor=util.query_Cursor(); adapter=new SimpleCursorAdapter(MainActivity.this,R.id.text_address}); listview.setAdapter(adapter); return true; } }); }
最后,介绍几个问题:
getWritableDatabase()与 getReadableDatabase() 区别:
两者均可对数据进行读写操作,不能按照字面意思的理解.
他们的区别在于,当电脑的磁盘满的时候,使用getWritableDatabase()操作数据库时会报异常,
而getReadableDatabase()不会报异常,而是等待磁盘容量释放后,而后又调用getWritableDatabase()获取数据库操作类对数据库进行操作. 也就是说一个在错误的时候报异常,一个不会报异常,我们一般会用哪一个可想而知了,当然要用报异常的方法.
对于simpleCursorAdapter的使用:
首先,其数据适配器配置的游标操作数据库的时候,不要关闭游标,或者关闭数据库,否则会报错.
其次,使用简单游标适配器的时候,查询出来的游标的数据字段中,必须包含一个字段_id,否则会报错.
如何提高数据库操作的效率?
1 当数据量不是很大的时候,我们使用原生提供的增删改查的方法与执行拼接的sql语句没有多大的区别.只是当数据量增大的时候,建议使用拼接的sql语句.
2 对数据库的操作,从本质上是对文件的操作,而每一次读取文件,都将变成一个耗时的操作,因此对于很多数据的操作,我们的做法是使用事务来进行,一次性的操作,提高效率.