【Android】13.1 用Android自带的API访问SQLite数据库

时间:2022-09-19 15:58:27

分类: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")]

这样就能正常显示简体中文,修改后项目中再也不会出现乱码了。

【Android】13.1 用Android自带的API访问SQLite数据库

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 = ;
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(), curs.GetInt());
Toast.MakeText(this, text, ToastLength.Short).Show();
};
} protected override void OnDestroy()
{
cursor.Close();
base.OnDestroy();
}
}
}