1 SQLite数据库
1.1 概念及基础知识
【
Sqlite数据库
作用:
用于存储n张数据表
数据表的作用:为了同时清晰存储多条复杂数据,如存储一张学生信息表
Ø sqlite数据库支持的数据类型(5种类型)
1) null 空
2) integer 整型
3) real 浮点型
4) text/varchar 字符串
5) blob 二进制
Ø sqlite支持的约束条件
1) primarykey:主键约束,非空且唯一
每张表都应该设置一个主键,找不到合适的主键的话,可以添加一个自增长列(只能是整型)来作为表的主键。
一张表最多只能有一个主键
2) notnull:非空约束
3) unique:唯一约束,可以为空
4) check:检查约束
5) default:默认约束
6) foreign key:外键约束
ü 主要用于维护引用的完整性(默认没有开启,要想使用必须手动开启)
ü 手动开启外键约束:PRAGMAforeign_keys = ON
ü 外键列的值必须在主键列中存在,否则就会出错。
ü 语法:字段名 数据类型 references表名(字段名)
特点:
手机端应用软件通常使用的数据库,轻量级数据库,只能处理一些数据的简单的增删改查操作
使用分类:
1. 操作本工程自己的数据库
即自己创建数据库,数据表,自己在本工程内进行增删改查
2. 已有现成的数据库文件,直接操作现成的数据库文件
在本工程内创建数据库以及数据表
1. 创建SqliteOpenHelper的子类
2. 重写子类中的相关方法
publicMyHelper(Context context) {
super(context,"abc.db",null,1);
// TODO Auto-generated constructor stub
}
/**
*SQLiteDatabase数据库对象的封装类,
* 通过此类执行sql语句
* 在此方法中通常执行创建表的操作
*
* 此方法的运行特点:
* 当通过当前的Helper对象调用getReadableDatabase或者getWriteableDatabase方法时
* 回去判断在data/data/程序包名/databases文件夹内是否存在数据库文件,如果
* 不存在运行此方法,如果存在,则不运行
* */
@Override
public void onCreate(SQLiteDatabasedb) {
// 创建表的实现方式:执行创建表的sql语句
/*
*create table 表名(列名 列中数据的类型 primary key autoincrement,列名2 列中数据的类型,... )
*primary key 主键列
*autoincrement 列中数据自动增长
*text 字符串类型
**/
Log.i("====", "===== onCreate");
db.execSQL("createtable ay (_id integer primary key autoincrement,name text,age integer)");
}
//一旦数据库的版本号发生变化时调用的方法
@Override
public void onUpgrade(SQLiteDatabasedb, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
Log.i("====", "===== onUpgrade"+oldVersion + " "+newVersion);
// db.execSQL("droptable ay"); //删除表
//
// onCreate(db);
}
什么时候使用数据库??
当需要在本地存储多条复杂数据时,可以考虑使用数据库进行管理
如存储n个学生的信息
1. 自产自销式
在本工程内部创建自身的数据库,由本工程自己去进行相关的增删改查操作
想要实现以上目标,必须通过SQLiteOpenHelper的类来实现
关于数据库中增删改查操作的实现:
/*
* 通常情况下,建议将所有的数据库操作封装为该类中的自定义方法,
* 方便后期统一修改管理
* */
public classMyHelper extends SQLiteOpenHelper {
/*
* 为后期初始MyHelper对象方便一些,并且,通常情况下, 多次创建MyHelper对象时
* 指定的数据库名字和版本号都是不变的,因此修改构造方法
* */
SQLiteDatabase db;
public MyHelper(Context context) {
/*
*2. 指定数据库文件的名字
*4. 数据库的版本号
**/
super(context, "test.db",null, 1);
// TODO Auto-generated constructor stub
db= getReadableDatabase();
}
//数据库初始化时运行的方法,只会在数据库文件不存在时运行一次,
//一旦数据文件存在,不再运行
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
Log.i("===", "===== onCreate onCreate");
/*
*通常数据库中不允许存在同名的表
*因此添加if not exists关键字,用于实现当数据库中不存在指定的ay表时创建表
*如果已存在,不再继续创建
**/
db.execSQL("createtable if not exists ay (_id integer primary key autoincrement,name text,ageinteger)");
}
//当数据库的版本发生变化时运行的方法,针对于版本变化,必须是newVersion>oldVersion
@Override
public void onUpgrade(SQLiteDatabase db, intoldVersion, int newVersion) {
// TODO Auto-generated method stub
db.execSQL("droptable if exists ay");
onCreate(db);
}
/*
* 通常情况下,建议将所有的数据库操作封装为该类中的自定义方法,
* 方便后期统一修改管理
* */
//1. 自定义方法,用于添加数据
public void add (String name,int age){
/*
*添加数据的sql语句
*insert into 表名(列名1,列名2...) values (值1,值2...)
*values中可以通过指定?先代表占位,稍后再给这个位置赋值
*稍后通过execSQL方法的参数二的Object数组给每一个问号赋值
*即前面的sql语句中有多少个?,Object数组中就应该有多少个元素
**/
db.execSQL("insertinto ay (name,age) values (?,?)", new Object[]{name,age});
}
//自定义方法,用于删除数据
public void delete (int _id){
/*
*删除的sql语句
*
*delete from 表名 删除表中所有的数据
*delete from 表名 where 条件表达式 删除符合条件的数据
*
**/
db.execSQL("deletefrom ay where _id = "+_id);
}
//自定义方法,用于实现数据的修改
public void update (int id,String name,intage){
/*
*修改的sql语句
*update 表名 set 列名1 = 值1,列名2 = 值2.... 修改表中的所有数据
*update 表名 set 列名1 = 值1,列名2 = 值2.... where 条件表达式 修改表中符合条件的数据
**/
db.execSQL("updateay set name = ?, age=? where _id = ?", new Object[]{name,age,id});
}
}
在MyHelper中定义好方法之后,只需在Activity中需要的位置通过MyHelper对象调用相应方法即可
】
1.2 Cursor类
【
列相关操作
getColumnCount():获取总列数
getColumnName(intcolumnIndex):获取指定位置的列名
getColumnIndex(StringcolumnName):获取列的索引位置
isNull(intcolumnIndex):指定位置的列是否为null
getType(intcolumnIndex):获取指定位置列的数据类型
getType(intcolumnIndex):获取指定位置列的数据类型
Cursor.FIELD_TYPE_INTEGER:int 类型
Cursor.FIELD_TYPE_FLOAT:float类型
Cursor.FIELD_TYPE_STRING:String类型
Cursor.FIELD_TYPE_BLOB:blob类型,即对象或二进制数据类型
记录相关操作
getCount():获取总记录数
getString(intcolumnIndex):获取指定列的String类型数据
getInt(intcolumnIndex):获取指定列的long类型数据
getLong(intcolumnIndex):获取指定列的long类型数据
getFloat(intcolumnIndex):获取指定列的float类型数据
getDouble(intcolumnIndex):获取指定列的double类型数据
位置移动
booleanmoveToNext():下一行移动
booleanmoveToPrevious():移到初始位置,第一条记录的上方
booleanmoveToPosition(int position):移动到指定位置
booleanmoveToFirst():移到第一条位置
booleanmoveToLast():移动到最后一条位置
move(intoffset):从当前位置向上或下移动n行,负值是向上移动,反之向下
】
1.3 重点数据的查询操作
【
查询:语法:select 列名1,列名2,...from 表名 [where 条件][group by 列名]
[having 条件][order by 列名 asc/desc][limit 初始位置,查询个数]
查询的实现:
//自定义方法,用于查询全表的所有数据
public ArrayList<Student> getAllStus (){
/*
*查询全表的sql语句:
*select * from 表名
**/
//为了能够获取查询的结果,选择使用rawQuery方法的到查询结果
/*
*参数1:要执行的查询的sql语句
*参数2:参数1 中如果存在?,通过此参数给?赋值,如果参数1中没有?,填null即可
**/
Cursor cursor =db.rawQuery("select * from ay", null);
ArrayList<Student> list = new ArrayList<Student>();
/*
*通过Cursor对象获取查询数据,并将查询数据添加到集合中,用于返回
*Cursor 游标
*特点:默认是指向查询结果表的第一行的上方,必须每次向下移动一行,每次移动后Cursor
*对象中可获取当前行的所有数据
*
*数据库中获取查询结果的原则:通过Cursor确定行数,再通过列名确定列数,即可将指定行指定列中的数据取出
**/
/*
*moveToNext方法用于让Cursor向下挪动一行,并且获取该行数据
*一旦返回值为false,代表已经移动到末尾,没有更多的数据了
**/
while(cursor.moveToNext()){
/*
* 通过cursor调用get方法获取本行指定类中的数据
* 方法的参数要求填写该列对应的列索引
* 可以通过getColumnIndex方法获取指定列名对应的列索引
* */
String name = cursor.getString(cursor.getColumnIndex("name"));
int age =cursor.getInt(cursor.getColumnIndex("age"));
list.add(new Student(name, age));
}
return list;
}
//查询全表数据,按照指定的模式排序,如按年龄排序,年龄大的靠前
public ArrayList<Student> getAllSortStus (){
/*
*查询全表的sql语句 (带排序效果):
*select * from 表名 order by 列名 asc或者desc
*asc 根据指定列中的值升序排列
*desc 根据指定列中的值降序排列
**/
Cursor cursor = db.rawQuery("select* from ay order by age desc", null);
ArrayList<Student> list = new ArrayList<Student>();
while(cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
int age = cursor.getInt(cursor.getColumnIndex("age"));
list.add(new Student(name, age));
}
return list;
}
//带条件的查询
public ArrayList<Student> getStu (String names){
/*
*查询表中指定的数据:
*select * from 表名 where 条件表达式 【 order by 列名 asc或者desc】
*【】代表可选择不写的内容
**/
/*
* 注意:一旦查询条件的值一个字符串类型的数据,那么建议用?替换此值,否则直接进行字符串拼接的话
* 需要给此数据添加‘’引起来才可以
**/
Cursor cursor =db.rawQuery("select * from ay where name = ?", new String[]{names});
ArrayList<Student> list = new ArrayList<Student>();
while(cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
int age = cursor.getInt(cursor.getColumnIndex("age"));
list.add(new Student(name, age));
}
return list;
}
//模糊查询
//如查询表中所有名字姓李的学生
public ArrayList<Student> likeStu (String names){
/*
*模糊查询:
*select * from 表名 where 列名 like 值
*
*值:
* % + 数据 查询的条件字符串必须以数据结尾 -- endsWith
* 数据 + % 查询的条件字符串必须以数据开头 ---startsWith
* %+数据+% 只要包含查询的条件字符串即可---contains
*
**/
/*
* 注意:一旦查询条件的值一个字符串类型的数据,那么建议用?替换此值,否则直接进行字符串拼接的话
* 需要给此数据添加‘’引起来才可以
**/
Cursor cursor = db.rawQuery("select* from ay where name like ?", new String[]{names+"%"});
ArrayList<Student> list = new ArrayList<Student>();
while(cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
int age = cursor.getInt(cursor.getColumnIndex("age"));
list.add(new Student(name, age));
}
return list;
}
】
1.3.1 通过内置方法实行查询
【
通过SQLiteDatabase 中封装好的方法实现数据库的增删改查:
增加:
/*
* 1. 要添加数据的表名
* 3. 要添加的数据,ContentValues对象
* 特点:可以存储多组键值对
* 键值对中的键是表中的列名
* 2. 任意添加表中一个列的列名即可。通过情况下添加主键列的名字
* 作用如:
* 指定表中可以为NULL的列的名字
* 当参数二和参数三同时传递null时,会报错
* 如果参数二为表中任意列名,参数三为null时,不会报错,可以成功添加数据,只不过添加的数据NULL
* */
ContentValuesvalues = new ContentValues();
//代表向表中参数一指定的列中加入参数二传递的数据
values.put("names", name);
/*
* 返回值代表新添加的数据对应的id值
* -1 添加失败
* */
long id = db.insert("tea","_id", values);
删除:
/*
* 1. table 表名
* 2. 指定删除的条件
* 3. 参数2的条件中?的值
* 返回值用于代表删除成功的条数
* */
int num = db.delete("tea", "name = ?", new String[]{name});
修改:
/*
*1. table 表名
*2. 要修改成的数据 ContenValues
*
* 3. 指定修改的条件
* 4. 参数3的条件中?的值
* */
ContentValues values = new ContentValues();
values.put("name", name);
//返回值代表修改成功的条数
db.update("tea", values, "name = ?", new String[]{tiao});
查询:
/*
* 1. 表名
* 2. String[] 指定要查询表中的哪些列,
* 如全表中有_id和name两列,如果只要获取所用name的值,不需要id的话,可以在数组中直接定“name”
* 如果要查询所有列,填null
* 3. String ,要与设置查询条件,不需要写where,直接写条件表达式即可
* 没条件,填null
*
* 4. 如果参数3中有代表占位的?,那么此参数用于设置?的值
*
* 5,6 指定分组的条件,即设置where 查询条件的另一种方式
* 7. 指定排序条件
* */
Cursor cursor = db.query("tea", null, null, null, null, null, null);
//要查新name为abc的值,query方法该如何封装??
// Cursor cursor =db.query("tea", null, "name = ?", new String[]{"abc"},null, null, "name asc");
】
1.4 通过方法实现增删改查操作
【
相对于db.execSql来说,更新、删除、插入操作能够返回相应的数字影响条数,能够响应是否操作成功了!
=插入= // 对于insert方法插入返回的是插入数据对应的id
long id= db.insert("tea", null,values);
=删除= intnum = db.delete("tea", "name=?", new String[] { name });
=更新= intnum = db.update("tea", values, "name=?", new String[] {name });
】
示例代码:
【
public class MyHelper extends SQLiteOpenHelper{
SQLiteDatabasedb;
public MyHelper(Context context) {
super(context, "stu.db",null, 1);
// TODO Auto-generated constructor stub
db = getReadableDatabase();
}
@Override
public voidonCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL("create table if not exists tea(_id integer primarykey autoincrement,name text)");
}
@Override
public voidonUpgrade(SQLiteDatabase db, intoldVersion, int newVersion) {
// TODO Auto-generated method stub
db.execSQL("drop table if exists tea");
onCreate(db);
}
// 插入数据
public voidadd(String name) {
ContentValuesvalues = new ContentValues();
values.put("name",name);
// 对于insert方法插入返回的是插入数据对应的id
long id= db.insert("tea",null, values);
}
// 删除数据
public voiddelete(String name) {
int num= db.delete("tea","name=?", new String[] { name });
}
// 更新数据
public voidupdate(String name) {
ContentValues values = new ContentValues();
values.put("name", name + name);
int num = db.update("tea", values, "name=?",new String[] {name });
}
// 查询数据
public ArrayList<String> query(Stringnames) {
ArrayList<String>data = new ArrayList<String>();
// columns:过滤的列名
// selection:查询条件
// selectionArgs:条件中所带的占位符参数值
// 全表查询
//Cursor cursor = db.query("tea", null, null,null, null, null,
// "namedesc");
Cursor cursor =db.query("tea", null, "name=?", new String[]{names},null, null, "name desc");
while(cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
data.add(name);
}
return data;
}
// 全表查询
public ArrayList<String> getAll() {
ArrayList<String>data = new ArrayList<String>();
// columns:过滤的列名
// selection:查询条件
// selectionArgs:条件中所带的占位符参数值
// 全表查询
Cursorcursor = db.query("tea",null, null,null, null,null, null);
while (cursor.moveToNext()) {
Stringname = cursor.getString(cursor.getColumnIndex("name"));
data.add(name);
}
return data;
}
}
】
1.5 数据库中完成对图片的操作
【
如何在数据库中完成对图片的存取操作??
1. 在创建表时,如果需要让某一列可以存储图片,那么只需将此列的类型设置为blob类型即可
/*
* blob 大数据类型,实际上就是byte[]类型,
* 此类型专门用来存储一些图片或者音频文件等
* */
db.execSQL("createtable img (_id integer primary key autoincrement, name text, ima blob)");
2. 在存入图片时:
//将bit对象转为byte数组
ByteArrayOutputStreambos = newByteArrayOutputStream();
bit.compress(CompressFormat.PNG,100, bos);
byte[] b = bos.toByteArray();
ContentValues values = new ContentValues();
values.put("name", name);
values.put("ima", b);
db.insert("img", "_id", values);
3. 在取出图片时:
Cursorc = db.query("img", null, "_id="+1, null, null, null, null);
if(c.moveToNext()) {
byte[] b =c.getBlob(c.getColumnIndex("ima"));
return BitmapFactory.decodeByteArray(b,0, b.length);
}
】
示例代码:
【
public class ImageHolderDB extends SQLiteOpenHelper {
private SQLiteDatabase db;
public ImageHolderDB(Context context) {
super(context, "image.db",null, 1);
// TODO Auto-generated constructor stub
db = getReadableDatabase();
}
@Override
public voidonCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
/*
* blob 大数据类型,实际上就是byte[]类型,
* 此类型专门用来存储一些图片或者音频文件等
* */
db.execSQL("create table if not exists img(_id integer primarykey autoincrement,name text,img blod)");
}
@Override
public voidonUpgrade(SQLiteDatabase db, intoldVersion, int newVersion) {
// TODO Auto-generated method stub
db.execSQL("drop table if exists img ");
onCreate(db);
}
//向数据库中添加数据
public voidadd(String name,Bitmap bit){
//将bit对象转为byte数组
ByteArrayOutputStreambos = new ByteArrayOutputStream();
bit.compress(CompressFormat.PNG, 100, bos);
byte[] b=bos.toByteArray();
ContentValuesvalues = new ContentValues();
values.put("name", name);
values.put("img", b);
db.insert("img","_id", values);
}
//读取图片流对象
public Bitmap getImage(){
Cursorcursor = db.query("img",null, "_id="+1,null, null,null, null);
if(cursor.moveToNext()){
byte[] b=cursor.getBlob(cursor.getColumnIndex("img"));
return BitmapFactory.decodeByteArray(b,0, b.length);
}
return null;
}
//测试大批量的数据批量插入时的效率问题测试
/**
* 执行SQl语句形式execSQL
*/
public voidaddBySql(){
long start = System.currentTimeMillis();
for(inti=0;i<1000;i++){
db.execSQL("insertinto img(name) values(?)",newObject[]{"sql item"+i});
}
long end =System.currentTimeMillis();
Log.i("===", "===== sql time"+(end-start));
}
/**
* 执行Insert方法
*/
public voidaddByInsert(){
long start = System.currentTimeMillis();
for(inti=0;i<1000;i++){
ContentValuesvalues = new ContentValues();
values.put("name", "insertitem"+i);
db.insert("img","_id", values);
}
long end = System.currentTimeMillis();
Log.i("===", "==== insert time"+(end-start));
}
事务运用:对于批量数据的操作,运行速度加较快
public void ByTransAction(){
long start =System.currentTimeMillis();
db.beginTransaction(); //开启事务
try {
for(int i=0;i<1000;i++){
db.execSQL("insertinto img(name) values (?)",new Object[]{"sql item"+i});
}
db.setTransactionSuccessful(); //给事务提供一个成功标识
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//结束事务
db.endTransaction();
long end = System.currentTimeMillis();
Log.i("===", "==== transaction time "+(end-start));
}
}
】
1.6 数据库中事务的作用
【
数据库中事务的作用:
1. 当大批量操作数据库时,如添加1000条数据,可以大大提高添加的速度
2. 可以确保大批量的操作要么全部执行成功,要么全部执行无效
事务的使用方式:
1. 在开始执行数据库操作之前通过db调用beginTransaction方法开启事务
2. 通过try catch将数据库操作部分代码包裹起来
3. 在try语句块的最末尾添加db. setTransactionSuccessful方法设置事务的成功标识
4. 在try catch语句后通过db调用endTransaction方法结束事务即可
代码如:
db.beginTransaction(); //开启事务
try {
for (int i=0;i<1000;i++) {
db.execSQL("insert into img (name) values (?)",new Object[]{"sqlitem"+i});
// if (i==100) {
// db.execSQL("insertinto imgs (name) values (?)",new Object[]{"sqlitem"+i});
// }
}
db.setTransactionSuccessful(); //给事务提供一个成功标识
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//结束事务,在结束时,会自动判断是否有记录过成功标识,如没有则将所有beginTransaction之后执行的代码//效果全部清空回滚掉
db.endTransaction();
】
1.7 提供给数据库使用的适配器
【
提供给数据库使用的适配器:
SimpleCursorAdapter
特点:
1. 数据源为Cursor类型
2. 不能控制blob类型数据的显示
使用方式:
通过构造方法初始化适配器后,通过setAdapter方法设置适配器即可
/*
* 1.Context 环境
* 2. int layout,用于指定列表中每个item条目对应的布局文件
* 3.Cursor类型,即适配器显示的数据源
* 注意:数据源的位置可以传null,一旦穿null的话,并不会崩溃,而是代表列表中不显示任何数据
* 4. String[] from 数据从哪来 ,添加表中的列名
* 5. int[] to 数据到哪去显示,布局中控件的id
* 6. flag标识
*
* 缺陷:不能显示图片
* */
adapter = new SimpleCursorAdapter(this, R.layout.item, c, new String[]{"name","age"}, new int[]{R.id.textView1,R.id.textView2}, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
lv.setAdapter(adapter);
更新SimpleCursorAdapter适配器的方法:
1. 得到新的Cursor查询结果
2. 通过adapter调用swapCursor方法更新数据源
3. 通过adapter调用notifyDataSetChanged方法刷新适配器的显示
Cursor c = helper.getData(currentPage*20);
//交换数据源,更新数据源
adapter.swapCursor(c);
adapter.notifyDataSetChanged();
查询数据表中指定位置指定条数的数据:
/*
* limit 从表中截取指定行数的数据
* limit后跟两个数据
* 其中第一个数字:起始行数的position位置
* 第二个数字:要截取多少行数据
* */
return db.rawQuery("select * from aylimit ?,?", newString[]{start+"","20"}); //分页
】
1.8 SimpleCursorAdapter与分页的实现
【
public class MyHelper extends SQLiteOpenHelper {
Contextcontext;
private SQLiteDatabase db;
public MyHelper(Context context) {
super(context, "name.db",null, 1);
// TODO Auto-generated constructor stub
this.context= context;
db = getReadableDatabase();
}
@Override
public voidonCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL("create table if not exists ay(_id integer primarykey autoincrement,name text,age text,img blob)");
// 在此处添加数据库中的初始数据
db.beginTransaction();
try {
ByteArrayOutputStreambos = new ByteArrayOutputStream();
Bitmapbit = BitmapFactory.decodeResource(context.getResources(),
R.drawable.ic_launcher);
bit.compress(CompressFormat.PNG, 100, bos); //将Bitmap对象转换为内存输出流对象
for (inti = 0; i < 3000; i++) {
ContentValuesvalues = new ContentValues();
values.put("name", "name"+ i);
values.put("age", "age"+ i);
values.put("img", bos.toByteArray());
db.insert("ay", "_id",values);
}
db.setTransactionSuccessful();
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
db.endTransaction();
}
@Override
public voidonUpgrade(SQLiteDatabase db, intoldVersion, int newVersion) {
// TODO Auto-generated method stub
db.execSQL("drop table if exists ay");
onCreate(db);
}
// 实现分页效果
public Cursor getData(int start) {
return db.rawQuery("select * fromay limit ?,?", new String[]{
start+ "", "20" });
}
// 获取分得的总页数
public intgetTotalPage() {
/*
* Cursor c = db.rawQuery("select * from ay",null); //获取查询结果的个数 int
* totalNum = c.getCount();
*/
// 查询ay表中的数据个数,并将数据个数赋值给c列
Cursorc = db.rawQuery("selectcount(*) as count from ay", null);
c.moveToNext();
int totalNum = c.getInt(c.getColumnIndex("count"));
int totalPage = 0;
if (totalNum % 20 == 0) {
totalPage= totalNum / 20;
}else {
totalPage= totalNum / 20 + 1;
}
return totalPage;
}
}
public class MainActivity extends Activity {
private ListView lv;
//专门配合数据库使用的适配器,该适配器在指定数据源时。类型为Cursor类型
SimpleCursorAdapteradapter;
MyHelperhelper;
int currentPage= 145; //用于记录当前的页数
int totalPage=0; //用于记录总页数
EditTextet_num_page;
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv =(ListView) findViewById(R.id.lv_mai_4x);
et_num_page=(EditText) this.findViewById(R.id.et_to_page);
helper = newMyHelper(this);
Cursorc = helper.getData(currentPage*20);
/*
* 1.Context 环境
* 2. int layout,用于指定列表中每个item条目对应的布局文件
* 3.Cursor类型,即适配器显示的数据源
* 注意:数据源的位置可以传null,一旦穿null的话,并不会崩溃,而是代表列表中不显示任何数据
* 4. String[] from 数据从哪来 ,添加表中的列名
* 5. int[] to 数据到哪去显示,布局中控件的id
* 6. flag标识
*
* 缺陷:不能显示图片
* */
adapter = new SimpleCursorAdapter(this,R.layout.item, c, new String[]{"name","age"},new int[]{R.id.textView1_4x,R.id.textView2_4x},SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
lv.setAdapter(adapter);
totalPage = helper.getTotalPage();
}
//按钮的点击事件
public voidclick(View v){
switch (v.getId()) {
case R.id.btn_privition: //跳转到上一页
if(currentPage>0){
currentPage--;
}
break;
case R.id.btn_next: //跳转到下一页
if(currentPage<(totalPage-1)){
currentPage++;
}
break;
case R.id.btn_tiao_page: //跳转到指定页
if(TextUtils.isEmpty(et_num_page.getText().toString())){
return;
}
int page_num =Integer.parseInt(et_num_page.getText().toString());
currentPage = page_num;
break;
}
Cursor c =helper.getData(currentPage*20);
//交换数据源,更新数据源
adapter.swapCursor(c);
adapter.notifyDataSetChanged();
}
}
】
1.9 操作SD卡中的数据文件
【
Sqlite数据库
使用方向二:
直接使用sd卡中现成的数据库文件进行操作,或者说,直接在指定的sd卡中或本工程中通过此方法创建一个数据库文件
即不通过使用SqliteOpenHelper对象操作数据库
通过SqliteDatabase对象调用以下方法实现上述目标
openDatabase(String path, CursorFactory factory, int flags)
参数1:path,数据文件的路径
参数2:factory,游标工厂,null代表使用默认的游标工厂对象
参数3:flags,访问模式
SQLiteDatabase.OPEN_READONLY:以只读的方式打开数据库
SQLiteDatabase.OPEN_READWRITE:以可读写的方式打开数据库
SQLiteDatabase.CREATE_IF_NECESSARY:当数据库不存在时,创建数据库
SQLiteDatabase.NO_LOCALIZED_COLLATORS:打开数据库时,不根据本地化语言对数据进行排序
openOrCreateDatabase(File file, CursorFactory factory)
等价于 SQLiteDatabase.openDatabase(dbFile.getAbsolutePath(), null,SQLiteDatabase.CREATE_IF_NECESSARY);
Cursor对象的常用方法:
Cursor类
列相关操作
getColumnCount():获取总列数
getColumnName(intcolumnIndex):获取指定位置的列名
getColumnIndex(StringcolumnName):获取列的索引位置
isNull(intcolumnIndex):指定位置的列是否为null
getType(intcolumnIndex):获取指定位置列的数据类型
getType(intcolumnIndex):获取指定位置列的数据类型
Cursor.FIELD_TYPE_INTEGER:int 类型
Cursor.FIELD_TYPE_FLOAT:float类型
Cursor.FIELD_TYPE_STRING:String类型
Cursor.FIELD_TYPE_BLOB:blob类型,即对象或二进制数据类型
记录相关操作
getCount():获取总记录数
getString(intcolumnIndex):获取指定列的String类型数据
getInt(intcolumnIndex):获取指定列的long类型数据
getLong(intcolumnIndex):获取指定列的long类型数据
getFloat(intcolumnIndex):获取指定列的float类型数据
getDouble(intcolumnIndex):获取指定列的double类型数据
位置移动
booleanmoveToNext():下一行移动
booleanmoveToPrevious():向上一行移动
booleanmoveToPosition(int position):移动到指定位置
booleanmoveToFirst():移到第一条位置
booleanmoveToLast():移动到最后一条位置
move(intoffset):从当前位置向上或下移动n行,负值是向上移动,反之向下
通过SqliteOpenHelper获取的数据库与通过openDatabase方法获取的数据库有什么区别??在什么情况下应该使用SqliteOpenHelper,在什么情况下可以使用openDatabase方法??
通过两种方式得到db对象之后,对db对象执行的增删改查的方式都是一样的
不同点在于: SqliteOpenHelper是控制本工程内自身的数据库
openDatabase 是打开sd卡中的数据库
总结起来:当需要操作本工程内的数据库,选择用SqliteOpenHelper
如果只是操作sd卡中的数据库,选用openDatabase方法
SimpleCursorAdapter的使用补充注意:
1. 该适配器中显示的Cursor对象对应的那张表的主键列的名字必须是_id
2. 在查询得到Cursor对象时,必须查询主键类的值,
如表中:_id,name,age 查询时只查name列,不行,SimpleCursorAdapter
会崩溃
】
示例代码:
【
public class MainActivity extends Activity {
SQLiteDatabase db;
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public voidclick(View v) {
switch (v.getId()) {
case R.id.button1:
// 获取sd卡中数据库文件对象
db = SQLiteDatabase.openDatabase(Environment
.getExternalStorageDirectory().getAbsolutePath()
+"/testss.db", null,SQLiteDatabase.CREATE_IF_NECESSARY);
//此方法的作用相当于调用了flags设置为SQLiteDatabase.CREATE_IF_NECESSARY的openDatabase方法的作用
//SQLiteDatabase.openOrCreateDatabase(file, factory);
break;
case R.id.button2:
//创建表
db.execSQL("createtable ay(_id integer primary key autoincrement,name text)");
break;
case R.id.button3:
//添加数据
db.execSQL("insertinto ay(name) values(?)",newObject[]{System.currentTimeMillis()+"a"});
break;
case R.id.button4:
//查询数据库中的数据
Cursorcur = db.rawQuery("select* from ay", null);
while(cur.moveToNext()){
Stringname = cur.getString(cur.getColumnIndex("name"));
Log.i("===", "=====all data name "+name);
}
//查询所有奇数行的数据
for(inti=1;i<cur.getCount(); i+=2){
cur.moveToPosition(i);
Stringname = cur.getString(cur.getColumnIndex("name"));
Log.i("===", "====name " +name);
}
break;
}
}
}
】