分类:C#、Android、VS2015;
创建日期:2016-02-26
一、简介
Android 内置了三种数据存取方式:SQLite数据库、文件、SharedPreferences。
这一章我们主要学习如何使用SQLite数据库存取数据。
1、SQLite是个什么档次的数据库
SQLite是一种免费的、开源的数据库,由于它独特的设计(把各种数据类型都转换为它自己内部处理的5种类型)导致其占用内存极少,因此很多项目都喜欢使用它。
Android集成了SQLite并内置了专门对SQLite操作的API,因此开发人员可在手机应用程序中直接使用它。
本章示例演示的是SQLite3,该版本内部仅有NULL、INTEGER、REAL(浮点数)、TEXT(字符串)、BLOB(二进制对象)共5种数据类型。换言之,它所处理的各种SQL数据类型保存时都会在内部自动转换为这5种数据类型,由于SQLite这种独特的设计,使它占用的内存极少且可移植性高,但是,也正因为如此,它提供的功能也很有限(只提供了最基本的数据库操作),这也是为什么说它仅是一种轻量级的数据库,非常适合于在嵌入式和移动应用开发中使用的原因。
如果将大型数据库(Oracle、SQL Server、DB2等)和SQLite相比,可以将前者理解为是一个“大型超市”,各种商品从低档到高档应有尽有,但占用的空间也大;而后者则是一个“小超市”,它仅销售大家喜欢的最基本最常用的商品,因此占用的空间也少。
但是,如果你希望它像大型超市一样什么东西都有,那你还是直接到大型超市去吧。
2、访问SQLite数据库的方式
用C#编写Android应用程序时,创建和访问SQLite数据库的方式非常多,这些都可以通过NuGet免费下载。这一章仅介绍几种最基本的方式。
(1)用Android内置的API实现
本章的【例13-1】、【例13-2】都是用这种方式实现的。
需要引用的命名空间:
using Android.Database;
using Android.Database.Sqlite;
这里需要说明一点,直接用SQL语法来构造SQL语句是最原始的实现方式,熟悉SQL语法的可能比较喜欢用这种方式。不过,用这种方式编写SQL语句实在是太费劲了,不但要记住各种SQL语法,而且查找SQL字符串中的错误也非常困难。特别是初学者,用这种方式编写出来的程序常常漏洞百出、bug一堆。
(2)用Xamarin提供的API实现
这是安装Xamarin for VS时内置的API,版本较早(1.0.66),利用它可通过ADO.NET访问sqlite数据库。上一章(第12章)的【例12-5】简单记事本功能就是用这种方式实现的。
早期版本需要引用的命名空间:
using Mono.Data.Sqlite;
新版本(1.0.99)支持.NET的各种版本,包括.NET 4.5、4.6以及LINQ、Entity Framework等,但目前尚不成熟,还在持续改进中,暂时先不使用它吧,等它完善了再玩也不晚。
新版本需要引用的命名空间:
using System.Data.Sql;
using System.Data.SqlClient;
(3)用sqlite-net实现
sqlite-net是用C#编写的操作SQLite数据库的轻量级的、开源的程序包,该程序包的C#源程序可直接通过NuGet直接下载到你的项目中。这个程序包最初的设计目的是为了用于操作iPhone应用程序中的SQlite的,但也可以在安卓应用程序中使用它。
sqlite-net的主要目标是设计一个快速而方便的数据库访问层。它是按照下面的这些原则来设计这个库的:
- 易于集成现有项目和MonoTouch项目。
- 对SQLite快速高效的轻量级包装(不会因为使用了它而引起查询的性能瓶颈)。
- 提供简单方法来安全执行CRUD操作(即:创建、读取、更新、删除),以及通过检索强类型检索方式来执行可带参数的查询,并快速返回结果。
- 内部包含一个轻量级的ORM反射驱动层,从而让你可以完全使用你自己定义的数据模型。
注意:sqlite-net并没有提供ADO.NET的完整实现,也没有提供SQLite的完整驱动。如果你需要这些,请使用Mono.Data.SQLite(即13.1介绍的内容)或者csharp-sqlite。
可利用NuGet免费下载sqlite-net程序包:
- sqlite-net:容量很小(最新的1.0.8版本解压后也仅有143KB)
- SQLiteNetExtensions:这个是sqlite-net的ORM扩展包(最新版本为1.3.0),支持1对1、1对n、n对1、n对n的关联操作。
但是,由于后来又出现了改进的SQLite.NET-PCL,所以这个用C# 3.0写的早期版本的sqlite-net就变得没用了。
(4)用SQLite.NET-PCL和SQLite.NET.Async-PCL实现
本章的【例13-3】、【例13-4】都是用这种方式实现的。
SQLite.Net-PCL在sqlte-net的基础上改进的程序包(最新的版本是3.1.1版),它除了支持同步和异步操作以外,还支持跨多种平台,例如Xamarin.Android、Xamarin.iOS(Classic)、Xamarin.iOS(Unified)、Windows Phone 8.1、Win8、Win10、……)等。
使用SQLite.Net-PCL时不需要下载sqlte-net。但是,为了区分原来的sqlte-net,这个包才又将其命名为SQLlite.NET-PCL。
PCL是英文“Portable Class Library”的缩写,含义是:用它设计的库可运行在Win8、Win10、Win32、Window Phone、monotouch、MonoAndroid、……等平台上。
SQLite.Net-PCL对sqlte-net的API做了一些修改。具体修改的地方有:
- 修改了SQLiteConnection类,使其可以跨多个平台。
- 提供了SQliteAsyncConnection,使其支持跨多个平台的异步操作。注意在这个类中,你编写的Task.Run模式的程序由SQLiteAsyncConnection来管理它。
- 修改了DateTime的串行化实现,以便可让其支持多区域。如果你要获取本地化的DateTime,需要调用dateTime.ToLocalTime()。
总的来说,如果你希望编写可跨Android、iOS、Windows Phone、……等多个平台的数据库公共操作类,建议用它来实现。
3、其他说明
不论你使用哪种数据库,也不论你采用哪种技术,一定要始终记住一点:手机应用程序是一种客户端程序,没有网络编程的基础你很难去完整地理解它。特别是别指望在实际项目中把数据库直接塞到手机中,你不会迷糊到用一个手机去当作服务器给很多人提供服务吧。在实际的大型应用中,数据库都是专门的服务器(到底需要多少个服务器那要看应用的规模了),而客户端仅仅是通过网络间接地和数据库服务器打交道来存取手机中需要的极小的一部分数据而已。那么,通过网络直接建立连接的是谁呢?是应用服务器中的程序对外公开的服务或接口,比如Web Service、Web API、……等。
但是,作为例子,都是把数据库也弄到手机上或者你自己的程序中,这样你调试和理解起来方便,添加、删除、复制数据库也方便,毕竟是学学、玩玩的阶段,反正记住一句话就行了:万丈高楼不是从中间凭空盖起来的,你只有学会和理解了它的最基本的用法,先学会盖一个小啪啪屋,然后再研究如何一点一点增加楼层的高度才靠谱。
二、观察本项目引用和下载的程序包
1、观察引用的.dll文件命名空间
到这一章为止,MyDemos项目已经添加了下列引用:
2、packages.config文件
再看看到这一章为止本项目已经通过NuGet下载了哪些程序包。MyDemos项目根目录下packages.config文件的内容如下:
<?xml version="1.0" encoding="utf-8"?> <packages> <package id="SQLite.Net.Async-PCL" version="3.1.1" targetFramework="monoandroid60" /> <package id="SQLite.Net.Core-PCL" version="3.1.1" targetFramework="monoandroid60" /> <package id="SQLite.Net-PCL" version="3.1.1" targetFramework="monoandroid60" /> <package id="Xamarin.Android.Support.v4" version="23.1.1.0" targetFramework="monoandroid60" /> <package id="Xamarin.Android.Support.v7.AppCompat" version="23.1.1.0" targetFramework="monoandroid60" /> <package id="Xamarin.Android.Support.v7.CardView" version="23.1.1.0" targetFramework="monoandroid60" /> <package id="Xamarin.Android.Support.v7.RecyclerView" version="23.1.1.0" targetFramework="monoandroid60" /> </packages>
三、本章示例主界面
1、运行截图
2、MainActivity.cs文件中本章对应的代码
chItems.Add(new Chapter() { ChapterName = "第13章 SQLite数据库访问", ChapterItems = new ChItem[] { new ChItem { type=typeof(ch1301MainActivity), Title="例13-1 SQLite基本用法1-SimpleCursorAdapter", Desc = "演示如何用SimpleCursorAdapter访问SQLite数据库" }, new ChItem { type=typeof(ch1302MainActivity), Title="例13-2 SQLite基本用法2-自定义CursorAdapter", Desc = "演示如何用自定义CursorAdapter访问SQLite数据库" }, new ChItem { type=typeof(ch1303MainActivity), Title="例13-3 SQLite基本用法3-SQLite.NET-PCL", Desc = "演示如何用SQLite.NET-PCL访问SQLite数据库" }, new ChItem { type=typeof(ch1303MainActivity), Title="例13-4 SQLite基本用法4-SQLite.NET.Async-PCL", Desc = "演示如何用SQLite.NET.Async-PCL访问SQLite数据库" }, } });