从头学Android之Android的数据存储--SQLite
应用场景:
在前面几讲我们讲了Android的数据存储使用文件或SharedPreferences存储数据,除此之外呢,有时候我们需要用到一个小型的数据库用于来保存我们的一些持久型的数据。所以在在Android平台上,集成了一个嵌入式关系型数据库—SQLite,SQLite3。因此中我们可以选择使用SQLite数据库存储数据。
SQLite概述:
SQLite,是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源世界著名的数据库管理系统来讲,它的处理速度比他们都快。SQLite第一个Alpha版本诞生于2000年5月. 至今已经有10个年头,SQLite也迎来了一个版本 SQLite 3已经发布。
SQLite所支持的数据类型:
SQLite,SQLite3支持 NULL、INTEGER、REAL(浮点数字)、TEXT(字符串文本)和BLOB(二进制对象)数据类型,虽然它支持的类型只有五种,但实际上sqlite3也接受varchar(n)、char(n)、decimal(p,s) 等数据类型,只不过在运算或保存时会转成对应的五种数据类型。
SQLite最大的特点是你可以把各种类型的数据保存到任何字段中,而不用关心字段声明的数据类型是什么。例如:可以在Integer类型的字段中存放字符串,或者在布尔型字段中存放浮点数,或者在字符型字段中存放日期型值。 但有一种情况例外:定义为INTEGER PRIMARY KEY的字段只能存储64位整数, 当向这种字段保存除整数以外的数据时,将会产生错误。 另外, SQLite 在解析CREATE TABLE 语句时,会忽略 CREATE TABLE 语句中跟在字段名后面的数据类型信息,如下面语句会忽略 name字段的类型信息:
CREATE TABLE person (personid integer primary key autoincrement, name varchar(20))
SQLite语句示范:
查询语句:select * from 表名 where 条件子句 group by 分组字句 having ... order by 排序子句
如:select * from person
select * from person order by id desc
select name from person group by name having count(*)>1
分页SQL与mysql类似,下面SQL语句获取5条记录,跳过前面3条记录
select * from Account limit 5 offset 3 或者 select * from Account limit 3,5
插入语句:insert into 表名(字段列表) values(值列表)。如: insert into person(name, age) values(‘张三’,3)
更新语句:update 表名 set 字段名=值 where 条件子句。如:update person set name=‘张三‘ where id=10
删除语句:delete from 表名 where 条件子句。如:delete from person where id=10
使用SQLiteOpenHelper对数据库进行版本管理
SQLiteOpenHelper
它是一个抽象类,用于对数据库版本进行控制。为了达到对数据库的一种管理我们必须继承自SQLiteOpenHelper这个抽象类。它是通过对数据库版本进行管理来实现一些需求。 为了实现对数据库版本进行管理,SQLiteOpenHelper类提供了两个重要的方法,分别是onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion),
下面将列出一些SQLiteOpenHelper类的一些常见方法:
两个构造方法:
方法名称 |
描述 |
public SQLiteOpenHelper (Context context, String name, SQLiteDatabase.CursorFactory factory, int version) |
|
public SQLiteOpenHelper (Context context, String name, SQLiteDatabase.CursorFactory factory, int version, DatabaseErrorHandler errorHandler) |
方法名称 |
描述 |
public void onOpen (SQLiteDatabase db) |
打开数据库 |
public abstract void onCreate (SQLiteDatabase db) |
初次使用软件时生成数据库表。在这个方法里面可以生成数据库表结构及添加一些应用使用到的初始化数据 |
public abstract void onUpgrade (SQLiteDatabase db, int oldVersion, int newVersion) |
用于升级软件时更新数据库表结构。在数据库的版本发生变化时会被调用,一般在软件升级时才需改变版本号 |
public synchronized SQLiteDatabase getWritableDatabase () |
得到一个可写的SQLiteDatabase实例 |
public synchronized SQLiteDatabase getReadableDatabase () |
得到一个可读的SQLiteDatabase实例 |
getWritableDatabase()和getReadableDatabase()的区别:
getWritableDatabase()和getReadableDatabase()方法都可以获取一个用于操作数据库的SQLiteDatabase实例。但getWritableDatabase() 方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用getWritableDatabase()打开数据库就会出错。getReadableDatabase()方法先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。
SQLiteDatabase
SQLiteDatabase代表的是一个数据库(底层就是一个数据库文件),一量应用程序获得了代表指定的数据库的SQLiteDatabase对象,接下来我们就可以用它来完成管理、操作数据库了。
几个静态方法获得SQLiteDatabase对象
方法名称 |
描述 |
public static SQLiteDatabase openDatabase (String path, SQLiteDatabase.CursorFactory factory, int flags, DatabaseErrorHandler errorHandler) |
打开path下的所代表的SQLite数据库 |
public static SQLiteDatabase openDatabase (String path, SQLiteDatabase.CursorFactory factory, int flags) |
打开path下的所代表的SQLite数据库 |
public static SQLiteDatabase openOrCreateDatabase (String path, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) |
打开path下的所代表的SQLite数据库 |
public static SQLiteDatabase openOrCreateDatabase (String path, SQLiteDatabase.CursorFactory factory) |
打开或者创建path下的所代表的SQLite数据库 |
public static SQLiteDatabase openOrCreateDatabase (File file, SQLiteDatabase.CursorFactory factory) |
打开或者创建file下的所代表的SQLite数据库 |
常用方法
方法名称 |
描述 |
public void execSQL (String sql) |
执行SQL语句 |
public void execSQL (String sql, Object[] bindArgs) |
执行带占位符的SQL语句 |
public long insert (String table, String nullColumnHack, ContentValues values) |
向table表中插入数据 |
public int update (String table, ContentValues values, String whereClause, String[] whereArgs) |
更新指定表table中的特定数据 |
public int delete (String table, String whereClause, String[] whereArgs) |
删除指定表(table)中的特定数据 |
public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) |
对执行数据表进行查询 |
public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) |
对执行数据表进行查询。参数说明: table: columns: selection: selectionArgs: groupBy: having: orderBy: |
public Cursor query (boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) |
对执行数据表进行查询 |
public Cursor rawQuery (String sql, String[] selectionArgs) |
执行带占位符的SQL查询。参数说明: sql: selectionArgs: |
public void beginTransaction () |
开始事务 |
public void endTransaction () |
结束事务 |
Cursor类
它是一个接口。Cursor的中文意思可以理解为一个游标,也类似于结果集,比如我们在JDBC中的ResultSet。它有以下的常用方法
方法名称 |
描述 |
public abstract void move(int offset) |
将记录指针向上或向下移动指定的行数。Offset为正向下移动,为负身上移动 |
public abstract boolean moveToFirst() |
将记录指定移动到第一行,如果移动成功返回true |
public abstract boolean moveToLast() |
将记录指针移动到最后一行。如果成功返回true |
public abstract boolean moveToNext() |
将记录指定移动到下一行,如果成功返回true |
public abstract boolean moveToPosition(int position) |
将记录指定移动到指定的行,如果移动成功则返回true |
public abstract boolean moveToPrevious(0 |
将记录指针将到上一行,如果移动成功则返回true |
熟悉完上面的所有API那么我们就来看如何使用这个轻型的SQLite来完成我们的数据持久化。
实例:
实现效果:
Activity主要代码:
- packagecom.jiahui.sqlite;
- importjava.util.ArrayList;
- importjava.util.Currency;
- importjava.util.HashMap;
- importjava.util.List;
- importjava.util.Map;
- importjava.util.zip.Inflater;
- importcom.jiahui.model.Person;
- importandroid.app.Activity;
- importandroid.content.ContentValues;
- importandroid.database.Cursor;
- importandroid.database.sqlite.SQLiteDatabase;
- importandroid.os.Bundle;
- importandroid.os.Handler;
- importandroid.os.Message;
- importandroid.view.LayoutInflater;
- importandroid.view.View;
- importandroid.view.ViewGroup;
- importandroid.widget.BaseAdapter;
- importandroid.widget.Button;
- importandroid.widget.EditText;
- importandroid.widget.ListView;
- importandroid.widget.SimpleAdapter;
- importandroid.widget.TextView;
- importandroid.widget.Toast;
- publicclassSQLiteDemoActivityextendsActivity{
- privateButtonbtnAdd;
- privateButtonbtnQueryAll;
- privateListViewlvpersons;
- privateEditTextedtname;
- privateEditTextedtage;
- privateList<Person>persons;
- privateHandlerhandler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemsg){
- //接到子线程发回来的数据,完成列表的显示
- List<Map<String,Object>>data=(List<Map<String,Object>>)msg.obj;
- SimpleAdaptersimpleAdapter=newSimpleAdapter(
- SQLiteDemoActivity.this,data,R.layout.list_item,
- newString[]{"id","name","age"},newint[]{
- R.id.tvid,R.id.tvname,R.id.tvage});
- lvpersons.setAdapter(simpleAdapter);
- }
- };
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- btnAdd=(Button)this.findViewById(R.id.btnAdd);
- btnQueryAll=(Button)this.findViewById(R.id.btnQueryAll);
- edtname=(EditText)this.findViewById(R.id.edtname);
- edtage=(EditText)this.findViewById(R.id.edtage);
- lvpersons=(ListView)this.findViewById(R.id.lvpersons);
- persons=newArrayList<Person>();
- DBHelperdbHelper=newDBHelper(this);
- finalSQLiteDatabasedatabase=dbHelper.getWritableDatabase();
- btnAdd.setOnClickListener(newView.OnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- ContentValuesvalues=newContentValues();
- values.put("name",edtname.getText().toString());
- values.put("age",edtage.getText().toString());
- longresult=database.insert("person",null,values);
- if(result!=-1){
- Toast.makeText(SQLiteDemoActivity.this,"增加数据成功",
- Toast.LENGTH_LONG).show();
- }
- }
- });
- btnQueryAll.setOnClickListener(newView.OnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- //查询数据可能花费太多时间交给子线程去做,在Handler完成数据的显示
- myThreadthread=newmyThread(database);
- thread.start();
- }
- });
- }
- classmyThreadextendsThread{
- privateSQLiteDatabasedatabase;
- publicmyThread(SQLiteDatabasedatabase){
- this.database=database;
- }
- publicvoidrun(){
- System.out.println("----------");
- Cursorcursor=database.query("person",newString[]{"_id",
- "name","age"},null,null,null,null,null);
- while(cursor.moveToNext()){
- Personperson=newPerson();
- person.setId(cursor.getInt(cursor.getColumnIndex("_id")));
- person.setName(cursor.getString(cursor.getColumnIndex("name")));
- person.setAge(cursor.getInt(cursor.getColumnIndex("age")));
- persons.add(person);
- }
- List<Map<String,Object>>data=newArrayList<Map<String,Object>>();
- for(inti=0;i<persons.size();i++){
- Map<String,Object>map=newHashMap<String,Object>();
- map.put("id",persons.get(i).getId());
- map.put("name",persons.get(i).getName());
- map.put("age",persons.get(i).getAge());
- data.add(map);
- System.out.println(persons.get(i));
- }
- Messagemsg=handler.obtainMessage();
- msg.obj=data;
- handler.sendMessage(msg);
- }
- }
- @Override
- protectedvoidonDestroy(){
- super.onDestroy();
- }
- }