【Android】13.1 用Android自带的API访问SQLite数据库
分类:C#、Android、VS2015;
创建日期:2016-02-26
一、简介
这一节我们先来看看如何直接用Android自带的API创建和访问SQLite数据库。
1、创建SQLite数据库
Android提供了一个SQLiteOpenHelper类(在Android.Database.Sqlite命名空间下),你只需要创建一个继承自SQLiteOpenHelper的类,就可以利用它轻松创建Sqlite数据库。
在继承自SQLiteOpenHelper的类中,要求至少需要实现下面的3个方法:
- 在构造函数中调用父类的构造函数。这个方法需要4个参数:
context:上下文环境(例如,一个Activity)
DatabaseName:数据库名
ICursorFactory:一个可选的游标工厂(通常将其设置为null)
DatabaseVersion:一个整数,表示你的数据库版本。
- 重写OnCreate方法。在这个重写的方法中,你可以利用SQLiteDatabase对象创建表和初始化数据。该方法可确保创建数据库的SQL语句只运行一次,这种功能是在SQLiteOpenHelper类中实现的。
- 重写OnUpgrage方法。该方法有3个参数:一个 SQLiteDatabase 对象,一个旧的版本号,一个新的版本号。利用它可以把一个数据库从旧的模型转变到新的模型。
具体用法见本节的示例。
数据库帮助器类创建完毕后,就可以在Activity中调用GetReadableDatabase()或者GetWriteableDatabase()方法获取SQLiteDatabase实例,具体调用哪个方法,取决于你是否需要改变数据库的内容。
例如:
public class MainActivity : Activity
{
private MyDb1Help db;
private ICursor cursor;
……
protected override void OnCreate(Bundle bundle)
{
……
db = new MyDb1Help(this);
cursor = db.ReadableDatabase.RawQuery("SELECT * FROM MyTable1", null);
……
}
}
上面这段代码会返回一个SQLiteDatabase类的实例,接下来就可以使用这个对象查询或者修改数据库了。
当你完成了对数据库的操作(例如你的 Activity 已经关闭),需要调用 SQLiteDatabase 的 Close() 方法释放掉数据库连接。
具体用法见本节的示例代码。
2、创建表
可通过调用 SQLiteDatabase实例的 execSQL() 方法执行 DDL 语句。例如:
db.execSQL("CREATE TABLE MyTable1 (……)"); //见例子中的具体代码
这条语句创建一个名为 MyTable1 的表,表有一个列名为“_id”,并且是主键,该列的值是会自动增长的整数(插入一行时SQLite会给这一列自动赋值),另外创建的列还有:name和age。
注意:SQLiteDatabase要求自动增量的字段名必须是“_id”而不是“id”或其他名称。
删除表时,可通过 execSQL() 方法执行 DROP TABLE 语句。
3、编辑数据(添加、删除、修改)
创建了数据库和表以后,就可以对数据表进行添加、删除、修改等操作了。
Android API提供了两种编辑数据的方式。
(1)方式1
方式1:使用 execSQL() 方法执行 INSERT、UPDATE、DELETE等语句来更新表数据。execSQL() 方法适用于所有不返回结果的 SQL 语句。例如:
db.execSQL("INSERT INTO MyTable1 (name, age) VALUES ('Zhang san', 24)");
(2)方式2
方式2:使用SQLiteDatabase对象的Insert()、Update()、Delete()方法。这些方法把SQL语句的一部分作为参数。例如:
ContentValues cv=new ContentValues();
cv.put(Constants.TITLE, "example title");
cv.put(Constants.VALUE, SensorManager.GRAVITY_DEATH_STAR_I);
db.insert("mytable", getNullColumnHack(), cv);
Update()方法有四个参数,分别是表名,表示列名和值的 ContentValues 对象,可选的 WHERE 条件和可选的填充 WHERE 语句的字符串,这些字符串会替换 WHERE 条件中的“?”标记。update() 根据条件,更新指定列的值,所以用 execSQL() 方法可以达到同样的目的。
WHERE 条件和其参数和已经使用过的其他 SQL APIs 类似。例如:
string[] parms=new String[] {"this is a string"};
db.update("widgets", replacements, "name=?", parms);
delete() 方法的用法和 update() 类似,使用表名、可选的 WHERE 条件和相应的填充 WHERE 条件的字符串。
4、查询数据
与 INSERT、UPDATE、DELETE类似,也有两种方式使用 SELECT 从 SQLite 数据库检索数据:
第1种方式是使用 RawQuery() 直接调用 SELECT 语句;
第2种方式是使用 Query() 方法构建一个查询。
(1)RawQuery()
RawQuery() 是最简单的查询数据的方法,通过这个方法可直接传递 SQL的 SELECT 语句。例如:
ICursor c=db.rawQuery(
"SELECT name FROM sqlite_master WHERE type='table' AND name='mytable'", null);
上面的代码查询 SQLite 系统表(sqlite_master)检查 table 表是否存在。返回值是一个 cursor 对象,这个对象的方法可以迭代查询结果。
但是,如果查询是动态的,使用这个方法会非常复杂。例如,当需要查询的列在程序编译的时候不能确定,这时候使用 query() 方法会方便很多。
(2)Query()
query() 方法用SELECT 语句的内容作为该方法的参数。比如:要查询的表名、要获取的字段名、WHERE 条件、用包含可选的位置参数去替代 WHERE 条件中位置参数的值、GROUP BY 条件、HAVING 条件等。
除了表名,其他参数都可以是 null。所以,以前的代码段可以可写成:
String[] columns={"ID", "inventory"};
String[] parms={"snicklefritz"};
Cursor result=db.query("widgets", columns, "name=?",parms, null, null, null);
二、SimpleCursorAdapter类
Android专门提供了一个简单的游标适配器类(SimpleCursorAdapter),利用该类可以从一个SQLite 数据库中查询数据并将其显示出来,其用法和ArrayAdapter相似。
SimpleCursorAdapter的用法很简单,只需要创建该类的实例并在构造函数中提供所需的参数 (例如游标和布局的信息),然后将查询结果分配给视图(例如ListView)即可。
SimpleCursorAdapter类的构造函数参数有:
Context:使用哪个Activity
Layout:布局文件中显示对应数据行的资源ID
ICursor:SQLite查询返回的游标。
From string array:游标中包含的字符串列。
To integer array:控件中显示对应行的id整型数组,游标会自动将当前读取的列绑定到这些对应的id表示的行上。
from和to必须有相同数量的条目,这是因为需要在“数据源”和“控件”之间建立一个一对一的映射:
// 与布局控件对应的列
string[] fromColumns = new string[] {"name"};
int[] toControlIDs = new int[] {Android.Resource.Id.Text1};
// 使用SimpleCursorAdapter创建适配器
listView.Adapter = new SimpleCursorAdapter (this, Android.Resource.Layout.SimpleListItem1, cursor,
fromColumns,
toControlIDs);
在SimpleCursorAdapter的构造函数中,必须为cursor读取的行指定一个Layout以及指定cursor中的哪一列应该被插入到layout对应行的哪个view中去。
实例化SimpleCursorAdaptery以后,SimpleCursorAdapter就会使用提供的layout将每一个Columns插入到对应的Views中,并在Cursor中为每一行创建一个View。
如果改变了可以被Adapter读取的底层数据,可通过NotifyDataSetChanged()通知相关的view刷新数据。
SimpleCursorAdapter是快速显示SQLite数据库中数据最简单的方式,但是,它只能通过绑定列的值来显示控件,而无法对行进行更改(例如显示/隐藏控件或更改属性等),该适配器一般适用于数据比较少的情况。
三、示例1—使用SimpleCursorAdapter访问SQLite
该示例演示SQLiteOpenHelper类和SimpleCursorAdapter类的基本用法。
1、运行截图
说明:如果你在运行时发现中文显示为乱码,只需要修改项目中Properties文件夹下的AssemblyInfo.cs文件,将下面的语句:
[assembly: AssemblyCulture("")]
改为:
[assembly: AssemblyCulture("zh-CN")]
这样就能正常显示简体中文,修改后项目中再也不会出现乱码了。
2、主要设计步骤
(1)添加ch1301_Main.axml文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ListView android:id="@+id/ch1301_listView1" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout>
(2)添加ch1301MyDb1.cs文件
using Android.Content; using Android.Database.Sqlite; namespace MyDemos.SrcDemos { public class ch1301MyDb1 : SQLiteOpenHelper { public static readonly string sql = "CREATE TABLE [MyTable1] (" + "[_id] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE," + "[name] TEXT NOT NULL UNIQUE," + "[age] INTEGER NOT NULL)"; public static readonly string dbName = "MyDb1.db"; public static readonly int dbVersion = 1; public ch1301MyDb1(Context context) : base(context, dbName, null, dbVersion) { } public override void OnCreate(SQLiteDatabase db) { db.ExecSQL(sql); db.ExecSQL("INSERT INTO MyTable1 (name,age) VALUES ('张三',23)"); db.ExecSQL("INSERT INTO MyTable1 (name,age) VALUES ('李四',22)"); db.ExecSQL("INSERT INTO MyTable1 (name,age) VALUES ('王五',19)"); db.ExecSQL("INSERT INTO MyTable1 (name,age) VALUES ('赵六',21)"); } public override void OnUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // 更改数据库版本的操作,如果无版本更改,此处不需要编写任何代码 } } }
(3)添加ch1301MainActivity.cs文件
using Android.App; using Android.OS; using Android.Widget; using Android.Database; namespace MyDemos.SrcDemos { [Activity(Label = "【例13-1】SQLite基本用法1")] public class ch1301MainActivity : Activity { private ICursor cursor; protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.ch1301_Main); ch1301MyDb1 db = new ch1301MyDb1(this); cursor = db.ReadableDatabase.RawQuery("SELECT * FROM MyTable1", null); var listView = FindViewById<ListView>(Resource.Id.ch1301_listView1); string[] fromColumns = { "name", "age" }; int[] toControlIDs = new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 }; listView.Adapter = new SimpleCursorAdapter(this, Android.Resource.Layout.SimpleListItem2, cursor, fromColumns, toControlIDs); listView.ItemClick += (s, e) => { var obj = listView.Adapter.GetItem(e.Position); var curs = (ICursor)obj; // 第0~2列的字段名:_id,name,age var text = string.Format("{0}({1}岁)", curs.GetString(1), curs.GetInt(2)); Toast.MakeText(this, text, ToastLength.Short).Show(); }; } protected override void OnDestroy() { cursor.Close(); base.OnDestroy(); } } }