《数据存储与访问》PPT课件.ppt

上传人:tia****nde 文档编号:12731176 上传时间:2020-05-20 格式:PPT 页数:177 大小:2.19MB
返回 下载 相关 举报
《数据存储与访问》PPT课件.ppt_第1页
第1页 / 共177页
《数据存储与访问》PPT课件.ppt_第2页
第2页 / 共177页
《数据存储与访问》PPT课件.ppt_第3页
第3页 / 共177页
点击查看更多>>
资源描述
第8章数据存储与访问,本章学习目标:,掌握SharedPreferences的使用方法掌握各种文件存储的区别与适用情况了解SQLite数据库的特点和体系结构掌握SQLite数据库的建立和操作方法,8.1简单存储,8.1.1SharedPreferencesSharedPreferences是一种轻量级的数据保存方式通过SharedPreferences开发人员可以将NVP(Name/ValuePair,名称/值对)保存在Android的文件系统中,而且SharedPreferences完全屏蔽了对文件系统的操作过程开发人员仅通过调用SharedPreferences中的函数就可以实现对NVP的保存和读取,8.1简单存储,8.1.1SharedPreferencesSharedPreferences不仅能够保存数据,还能够实现不同应用程序间的数据共享SharedPreferences支持三种访问模式私有(MODE_PRIVATE):仅创建SharedPreferences的程序有权限对其进行读取或写入全局读(MODE_WORLD_READABLE):不仅创建程序可以对其进行读取或写入,其它应用程序也具有读取操作的权限,但没有写入操作的权限全局写(MODE_WORLD_WRITEABLE):所有程序都可以对其进行写入操作,但没有读取操作的权限,8.1简单存储,8.1.1SharedPreferences在使用SharedPreferences前,先定义SharedPreferences的访问模式下面的代码将访问模式定义为私有模式1publicstaticintMODE=MODE_PRIVATE;有的时候需要将SharedPreferences的访问模式设定为即可以全局读,也可以全局写,这就需要将两种模式写成下面的方式35publicstaticintMODE=Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITEABLE;,8.1简单存储,8.1.1SharedPreferences除了定义SharedPreferences的访问模式,还要定义SharedPreferences的名称,这个名称也是SharedPreferences在Android文件系统中保存的文件名称一般将SharedPreferences名称声明为字符串常量,这样可以在代码中多次使用1publicstaticfinalStringPREFERENCE_NAME=SaveSetting;使用SharedPreferences时需要将访问模式和SharedPreferences名称作为参数传递到getSharedPreferences()函数,则可获取到SharedPreferences实例1SharedPreferencessharedPreferences=getSharedPreferences(PREFERENCE_NAME,MODE);,8.1简单存储,8.1.1SharedPreferences在获取到SharedPreferences实例后,可以通过SharedPreferences.Editor类对SharedPreferences进行修改,最后调用commit()函数保存修改内容SharedPreferences广泛支持各种基本数据类型,包括整型、布尔型、浮点型和长型等,8.1简单存储,8.1.1SharedPreferences如果需要从已经保存的SharedPreferences中读取数据,同样是调用getSharedPreferences()函数,并在函数第1个参数中指明需要访问的SharedPreferences名称,最后通过get()函数获取保存在SharedPreferences中的NVPget()函数的第1个参数是NVP的名称第2个参数是在无法获取到数值的时候使用的缺省值,8.1简单存储,8.1.2示例下面将通过SimplePreferenceDemo示例介绍SharedPreferences的文件保存位置和保存格式下图是SimplePreferenceDemo示例的用户界面,8.1简单存储,8.1.2示例用户在界面上的输入信息,在Activity关闭时通过SharedPreferences进行保存。当应用程序重新开启时,再通过SharedPreferences将信息读取出来,并重新呈现在用户界面上SimplePreferenceDemo示例运行并通过“回退键”退出后,通过FileExplorer查看/data/data下的数据,Android系统为每个应用程序建立了与包同名的目录,用来保存应用程序产生的数据文件,包括普通文件、SharedPreferences文件和数据库文件等SharedPreferences产生的文件就保存在/data/data/shared_prefs目录下,8.1简单存储,8.1.2示例在本示例中,shared_prefs目录中生成了一个名为SaveSetting.xml的文件如图8.2所示,保存在/data/data/edu.hrbeu.SimplePreferenceDemo/shared_prefs目录下这个文件就是保存SharedPreferences的文件,文件大小为170字节,在Linux下的权限为“-rw-rw-rw”,8.1简单存储,8.1.2示例在Linux系统中,文件权限分别描述了创建者、同组用户和其它用户对文件的操作限制。x表示可执行,r表示可读,w表示可写,d表示目录,-表示普通文件因此,“-rw-rw-rw”表示SaveSetting.xml可以被创建者、同组用户和其它用户进行读取和写入操作,但不可执行产生这样的文件权限与程序人员设定的SharedPreferences的访问模式有关,“-rw-rw-rw”的权限是“全局读+全局写”的结果如果将SharedPreferences的访问模式设置为私有,则文件权限将成为“-rw-rw-”,表示仅有创建者和同组用户具有读写文件的权限,8.1简单存储,8.1.2示例SaveSetting.xml文件是以XML格式保存的信息,内容如下,8.1简单存储,8.1.2示例SimplePreferenceDemo示例在onStart()函数中调用loadSharedPreferences()函数,读取保存在SharedPreferences中的姓名、年龄和身高信息,并显示在用户界面上当Activity关闭时,在onStop()函数调用saveSharedPreferences(),保存界面上的信息SimplePreferenceDemoActivity.java的完整代码如下,8.1简单存储,8.1.2示例,8.1简单存储,8.1.2示例,8.1简单存储,8.1.2示例,8.1简单存储,8.1.2示例,首先下载附件adb_win.zip,解压获得文件。将所有文件复制粘贴到电脑C盘/Windows/system32里面。在命令符终端输入adbshell,即可连接。连接成功以后,你输入任何shell脚本命令都将是在手机系统中执行。,调试中遇到问题:使用cmd-adbshell时,显示错误为adb不是内部命令或外部命令,也不是可运行的程序或批处理文件。解决步骤:,打开xml文件步骤:,打开xml文件步骤:,打开xml文件步骤:,打开xml文件步骤:,8.2文件存储,虽然SharedPreferences能够为开发人员简化数据存储和访问过程,但直接使用文件系统保存数据仍然是Android数据存储中不可或缺的组成部分Android使用Linux的文件系统,开发人员可以建立和访问程序自身建立的私有文件,也可以访问保存在资源目录中的原始文件和XML文件,还可以将文件保存在TF卡等外部存储设备中,8.2文件存储,8.2.1内部存储Android系统允许应用程序创建仅能够自身访问的私有文件,文件保存在设备的内部存储器上,在Android系统下的/data/data/files目录中Android系统不仅支持标准Java的IO类和方法,还提供了能够简化读写流式文件过程的函数这里主要介绍两个函数openFileOutput()openFileInput(),8.2文件存储,8.2.1内部存储openFileOutput()函数openFileOutput()函数为写入数据做准备而打开文件如果指定的文件存在,直接打开文件准备写入数据如果指定的文件不存在,则创建一个新的文件openFileOutput()函数的语法格式如下publicFileOutputStreamopenFileOutput(Stringname,intmode)第1个参数是文件名称,这个参数不可以包含描述路径的斜杠第2个参数是操作模式,Android系统支持四种文件操作模式函数的返回值是FileOutputStream类型,8.2文件存储,8.2.1内部存储openFileOutput()函数四种文件操作模式,8.2文件存储,8.2.1内部存储openFileOutput()函数使用openFileOutput()函数建立新文件的示例代码如下1StringFILE_NAME=fileDemo.txt;2FileOutputStreamfos=openFileOutput(FILE_NAME,Context.MODE_PRIVATE)3Stringtext=“Somedata”;4fos.write(text.getBytes();5fos.flush();6fos.close();代码首先定义文件的名称为fileDemo.txt然后使用openFileOutput()函数以私有模式建立文件,并调用write()函数将数据写入文件,调用flush()函数将缓冲中的数据写入文件,最后调用close()函数关闭FileOutputStream,8.2文件存储,8.2.1内部存储openFileOutput()函数为了提高文件系统的性能,一般调用write()函数时,如果写入的数据量较小,系统会把数据保存在数据缓冲区中,等数据量积攒到一定程度时再将数据一次性写入文件因此,在调用close()函数关闭文件前,务必要调用flush()函数,将缓冲区内所有的数据写入文件如果开发人员在调用close()函数前没有调用flush(),则可能导致部分数据丢失,8.2文件存储,8.2.1内部存储openFileInput()函数openFileInput()函数为读取数据做准备而打开文件openFileInput()函数的语法格式如下publicFileInputStreamopenFileInput(Stringname)第1个参数也是文件名称,同样不允许包含描述路径的斜杠使用openFileInput()函数打开已有文件,并以二进制方式读取数据的示例代码如下,8.2文件存储,8.2.1内部存储openFileInput()函数上面的两部分代码在实际使用过程中会遇到错误提示,因为文件操作可能会遇到各种问题而最终导致操作失败,因此代码应该使用try/catch捕获可能产生的异常.,8.2文件存储,8.2.1内部存储FileText是用来演示在内部存储器上进行文件写入和读取的示例。用户界面如下图所示,用户将需要写入的数据添加在EditText中,通过“写入文件”按钮将数据写入到/data/data/edu.crazyit.io/FileText/files/crazyit.txt文件中通过“读取文件”按钮,程序会读取crazyit.txt文件的内容,并显示在界面下方的白色区域中,8.2文件存储,8.2文件存储,8.2.1内部存储InternalFileDemo示例的核心代码,8.2文件存储,8.2.1内部存储,8.2文件存储,8.2.1内部存储,8.2文件存储,8.2.1内部存储,8.2文件存储,8.2.1内部存储程序运行后,在/data/data/edu.hrbeu.InternalFileDemo/files/目录下,找到了新建立的fileDemo.txt文件,下图所示从文件权限上进行分析fileDemo.txt文件,“-rw-rw-”表明文件仅允许文件创建者和同组用户读写,其它用户无权使用文件的大小为9个字节,保存的数据为“Somedata”,8.2文件存储,8.2.2外部存储Android的外部存储设备一般指MicroSD卡,又称T-Flash,是一种广泛使用于数码设备的超小型记忆卡下图是东芝出品的32GMicroSD卡,8.2文件存储,8.2.2外部存储MicroSD卡适用于保存大尺寸的文件或者是一些无需设置访问权限的文件如果用户希望保存录制的视频文件和音频文件,因为Android设备的内部存储空间有限,所以使用MicroSD卡则是非常适合的选择但如果需要设置文件的访问权限,则不能够使用MicroSD卡,因为MicroSD卡使用FAT(FileAllocationTable)文件系统,不支持访问模式和权限控制Android的内部存储器使用的是Linux文件系统,则可通过文件访问权限的控制保证文件的私密性,8.2文件存储,8.2.2外部存储Android模拟器支持SD卡的模拟,在模拟器建立时可以选择SD卡的容量,如下图所示,在模拟器启动时会自动加载SD卡,8.2文件存储,8.2.2外部存储正确加载SD卡后,SD卡中的目录和文件被映射到/mnt/sdcard目录下因为用户可以加载或卸载SD卡,所以在编程访问SD卡前首先需要检测/mnt/sdcard目录是否可用如果不可用,说明设备中的SD卡已经被卸载。如果可用,则直接通过使用标准的java.io.File类进行访问SDcardFileDemo示例用来说明如何将数据保存在SD卡中首先通过“生产随机数列”按钮生产10个随机小数,然后通过“写入SD卡”按钮将生产的数据保存在SD卡的根目录下,也就是Android系统的/mnt/sdcard目录下,8.2文件存储,8.2.2外部存储SDcardFileDemo用户界面图,8.2文件存储,8.2.2外部存储SDcardFileDemo示例运行后,在每次点击“写入SD卡”按钮后,都会在SD卡中生产一个新文件,文件名各不相同,如下图所示,8.2文件存储,8.2.2外部存储SDcardFileDemo示例与InternalFileDemo示例的核心代码比较相似,不同之处在于代码中添加了/mnt/sdcard目录存在性检查(代码第7行),并使用“绝对目录+文件名”的形式表示新建立的文件(代码第8行),并在写入文件前对文件的存在性和可写入性进行检查(代码第12行)为了保证在SD卡中多次写入时文件名不会重复,在文件名中使用了唯一且不重复的标识(代码第5行),这个标识通过调用System.currentTimeMillis()函数获得,表示从1970年00:00:00到当前所经过的毫秒数SDcardFileDemo示例的核心代码如下,8.2文件存储,8.2.2外部存储,8.2文件存储,8.2.2外部存储,8.2文件存储,8.2.2外部存储程序在模拟器中运行前,还必须在AndroidManifest.xml中注册两个用户权限,分别是加载卸载文件系统的权限和向外部存储器写入数据的权限AndroidManifest.xml的核心代码如下,8.2文件存储,8.2.3资源文件开发人员除了可以在内部和外部存储设备上读写文件以外,还可以访问在/res/raw和/res/xml目录中的原始格式文件和XML文件,这些文件是程序开发阶段在工程中保存的文件原始格式文件可以是任何格式的文件,例如视频格式文件、音频格式文件、图像文件或数据文件等等在应用程序编译和打包时,/res/raw目录下的所有文件都会保留原有格式不变。而/res/xml目录下一般用来保存格式化数据的XML文件,则会在编译和打包时将XML文件转换为二进制格式,用以降低存储器空间占用和提高访问效率,在应用程序运行的时候会以特殊的方式进行访问,8.2文件存储,8.2.3资源文件ResourceFileDemo示例演示了如何在程序运行时访问资源文件当用户点击“读取原始文件”按钮时,程序将读取/res/raw/raw_file.txt文件,并将内容显示在界面上,如下图所示,8.2文件存储,8.2.3资源文件当用户点击“读取XML文件”按钮时,程序将读取/res/xml/people.xml文件,也将内容显示在界面上,如下图所示,8.2文件存储,8.2.3资源文件读取原始格式文件首先需要调用getResource()函数获得资源实例,然后通过调用资源实例的openRawResource()函数,以二进制流的形式打开指定的原始格式文件。在读取文件结束后,调用close()函数关闭文件流ResourceFileDemo示例中读取原始格式文件的核心代码如下,8.2文件存储,8.2.3资源文件,8.2文件存储,8.2.3资源文件代码第8行的newString(reader,utf-8),表示以UTF-8的编码方式从字节数组中实例化一个字符串如果程序开发人员需要新建/res/raw/raw_file.txt文件,则需要选择使用UTF-8编码方式,否则程序运行时会产生乱码选择的方法是在raw_file.txt文件上点击右键,选择“Properties”打开raw_file.txt文件的属性设置框,然后在“Resource”栏下的“Textfileencoding”中,选择“Other:UTF-8”,如下图所示,8.2文件存储,8.2.3资源文件选择raw_file.txt文件编码方式,8.2文件存储,8.2.3资源文件/res/xml目录下的XML文件与其它资源文件有所不同,程序开发人员不能够以流的方式直接读取,其主要原因在于Android系统为了提高读取效率,减少占用的存储空间,将XML文件转换为一种高效的二进制格式如何在程序运行时读取/res/xml目录下的XML文件首先在/res/xml目录下创建一个名为people.xml的文件XML文件定义了多个元素,每个元素都包含三个属性name、age和height,分别表示姓名、年龄和身高/res/xml/people.xml文件代码如下,8.2文件存储,8.2.3资源文件读取XML格式文件首先通过调用资源实例的getXml()函数,获取到XML解析器XmlPullParserXmlPullParser是Android平台标准的XML解析器,这项技术来自一个开源的XML解析API项目XMLPULLResourceFileDemo示例中关于读取XML文件的核心代码如下,8.2文件存储,8.2.3资源文件读取XML格式文件,8.2文件存储,8.2.3资源文件读取XML格式文件,8.2文件存储,8.2.3资源文件读取XML格式文件代码第1行通过资源实例的getXml()函数获取到XML解析器第4行的parser.next()方法可以获取到高等级的解析事件,并通过对比确定事件类型,XML事件类型参考下表,8.2文件存储,8.2.3资源文件读取XML格式文件第5行使用getName()函数获得元素的名称第10行使用getAttributeCount()函数获取元素的属性数量第12行通过getAttributeName()函数得到属性名称最后在第14行到第19行代码中,通过分析属性名获取到正确的属性值,并在第23行将属性值整理成需要显示的信息,8.3数据库存储,8.3.1SQLite数据库SQLite是一个2000年由D.RichardHipp发布的开源嵌入式关系数据库普通数据库的管理系统比较庞大和复杂,会占用了较多的系统资源轻量级数据库SQLite的特点比传统数据库更适合用于嵌入式系统占用资源少,运行高效可靠,可移植性强提供了零配置(zero-configuration)运行模式,8.3数据库存储,8.3.1SQLite数据库SQLite数据库的优势可以嵌入到使用它的应用程序中提高了运行效率屏蔽了数据库使用和管理的复杂性客户端和服务器在同一进程空间运行完全不需要进行网络配置和管理减少了网络调用所造成的额外开销简化了数据库的管理过程应用程序更加易于部署和使用只需要把SQLite数据库正确编译到应用程序中,8.3数据库存储,8.3.1SQLite数据库SQLite数据库采用了模块化设计,模块将复杂的查询过程分解为细小的工作进行处理SQLite数据库由8个独立的模块构成,这些独立模块又构成了三个主要的子系统,8.3数据库存储,8.3.1SQLite数据库接口由SQLiteCAPI组成,因此无论是应用程序、脚本,还是库文件,最终都是通过接口与SQLite交互编译器在编译器中,分词器和分析器对SQL语句进行语法检查,然后把SQL语句转化为便于底层处理的分层数据结构,这种分层的数据结构称为“语法树”然后把语法树传给代码生成器进行处理,生成一种用于SQLite的汇编代码,最后由虚拟机执行,8.3数据库存储,8.3.1SQLite数据库虚拟机SQLite数据库体系结构中最核心的部分是虚拟机,也称为虚拟数据库引擎(VirtualDatabaseEngine,VDBE)与Java虚拟机相似,虚拟数据库引擎用来解释并执行字节代码虚拟数据库引擎的字节代码由128个操作码构成,这些操作码主要用以对数据库进行操作,每一条指令都可以完成特定的数据库操作,或以特定的方式处理栈的内容,8.3数据库存储,8.3.1SQLite数据库后端后端由B-树、页缓存和操作系统接口构成,B-树和页缓存共同对数据进行管理B-树的主要功能就是索引,它维护着各个页面之间复杂的关系,便于快速找到所需数据页缓存的主要作用是通过操作系统接口在B-树和磁盘之间传递页面,8.3数据库存储,8.3.1SQLite数据库移植性可以运行在Windows、Linux、BSD、MacOS和一些商用Unix系统,比如Sun的Solaris或IBM的AIX嵌入式操作系统下,比如QNX、VxWorks、PalmOS、Symbin和WindowsCESQLite的核心大约有3万行标准C代码,因为模块化的设计使这些代码非常易于理解,8.3数据库存储,8.3.2手动建库在Android系统中,每个应用程序的SQLite数据库被保存在各自的/data/data/databases目录下缺省情况下,所有数据库都是私有的,仅允许创建数据库的应用程序访问,如果需要共享数据库则可以使用ContentProvider虽然应用程序完全可以在代码中动态建立SQLite数据库,但使用命令行手工建立和管理数据库仍然是非常重要的内容,对于调试使用数据库的应用程序非常有用,8.3数据库存储,8.3.2手动建库手动建立数据库指的是使用sqlite3工具,通过手工输入命令行完成数据库的建立过程sqlite3是SQLite数据库自带的一个基于命令行的SQL命令执行工具,并可以显示命令执行结果AndroidSDK的tools目录有sqlite3工具,同时,该工具也被集成在Android系统中下面的内容将介绍如何连接到模拟器中的Linux系统,并在Linux系统中启动sqlite3工具,在Android程序目录中建立数据库和数据表,并使用命令在数据表中添加、修改和删除数据,8.3数据库存储,8.3.2手动建库使用adbshell命令连接到模拟器的Linux系统,在Linux命令提示符下输入sqlite3可启动sqlite3工具启动sqlite3后会显示SQLite的版本信息,显示内容如下,8.3数据库存储,8.3.2手动建库在启动sqlite3工具后,提示符从“#”变为“sqlite”,表示用户进入SQLite数据库交互模式,此时可以输入命令建立、删除或修改数据库的内容正确退出sqlite3工具的方法是使用.exit命令,8.3数据库存储,8.3.2手动建库原则上,每个应用程序的数据库都保存在各自的/data/data/databases目录下但如果使用手工方式建立数据库,则必须手工建立数据库目录,目前版本无需修改数据库目录的权限,8.3数据库存储,8.3.2手动建库在SQLite数据库中,每个数据库保存在一个独立的文件中使用“sqlite3+文件名”的方式打开数据库文件,如果指定的文件不存在,sqlite3工具则自动创建新文件下面的代码将创建名为people的数据库,在文件系统中将产生一个名为people.db的数据库文件,8.3数据库存储,8.3.2手动建库下面的代码在数据库中,构造了一个名为peopleinfo的表使用createtable命令,关系模式为peopleinfo(_id,name,age,height)表包含四个属性,_id是整型的主键;name表示姓名,字符型,notnull表示属性值一定要填写,不可以为空值;age表示年龄,整数型;height表示身高,浮点型,8.3数据库存储,8.3.2手动建库为了确认数据表是否创建成功,可以使用.tables命令,显示当前数据库中的所有表从下面的代码中可以观察到,当前的数据库中仅有一个名为peopleinfo的表,8.3数据库存储,8.3.2手动建库也可以使用.schema命令查看建立表时使用的SQL命令如果当前数据库中包含多个表,则可以使用.schema表名的形式,显示指定表的建立命令,8.3数据库存储,8.3.2手动建库下一步是向peopleinfo表中添加数据,使用insertintovalues命令在下面的代码成功运行后,数据库的peopleinfo表将有三条数据,内容如下表所示1sqliteinsertintopeopleinfovalues(null,Tom,21,1.81);2sqliteinsertintopeopleinfovalues(null,Jim,22,1.78);3sqliteinsertintopeopleinfovalues(null,Lily,19,1.68);因为_id是自动增加的主键,因此在输入null后,SQLite数据库会自动填写该项的内容,8.3数据库存储,8.3.2手动建库在数据添加完毕后,使用select命令,显示peopleinfo数据表中的所有数据信息,命令格式为select属性from表名下面的代码用来显示peopleinfo表的所有数据,8.3数据库存储,8.3.2手动建库上面的查询结果看起来不是很直观,使用表格方式显示更应更符合习惯,因此可以使用.mode命令更改结果输出格式.mode命令除了支持常见的column格式外,还支持csv格式、html格式、insert格式、line格式、list格式、tabs格式和tcl格式下面使用column格式显示peopleinfo数据表中的数据信息,8.3数据库存储,8.3.2手动建库更新数据可以使用update命令,命令格式为update表名set属性=”新值”where条件更新数据后,同样使用select命令显示数据,确定数据是否正确更新下面的代码将Lily的身高更新为1.88,8.3数据库存储,8.3.2手动建库删除数据可以使用delete命令命令格式为deletefrom表名where条件下面的代码将_id为3数据从表peopleinfo中删除,8.3数据库存储,8.3.2手动建库sqlite3工具还支持很多命令,可以使用.help命令查询sqlite3的命令列表,也可以参考下表,8.3数据库存储,8.3.2手动建库,8.3数据库存储,8.3.3代码建库在代码中动态建立数据库是比较常用的方法例如在程序运行过程中,当需要进行数据库操作时,应用程序会首先尝试打开数据库,此时如果数据库并不存在,程序则会自动建立数据库,然后再打开数据库在编程实现时,一般将所用对数据库的操作都封装在一个类中,因此只要调用这个类,就可以完成对数据库的添加、更新、删除和查询等操作,8.3数据库存储,8.3.3代码建库下面内容是DBAdapter类的部分代码,封装了数据库的建立、打开和关闭等操作,8.3数据库存储,8.3.3代码建库,8.3数据库存储,8.3.3代码建库,8.3数据库存储,8.3.3代码建库从代码的第2行到第9行可以看出,在DBAdapter类中首先声明了数据库的基本信息,包括数据库的文件名称、表名称和版本号,以及数据库表的属性名称从这些基本信息上不难发现,这个数据库与前一小节手动建立的数据库是完全相同的代码第11行声明了SQLiteDatabase的实例SQLiteDatabase类封装了较多的方法,用以建立、删除数据库,执行SQL命令,对数据进行管理等工作,8.3数据库存储,8.3.3代码建库代码第13行声明了一个非常重要的帮助类SQLiteOpenHelper,这个帮助类可以辅助建立、更新和打开数据库虽然在代码第21行定义了open()函数用来打开数据库,但open()函数中并没有任何对数据库进行实际操作的代码,而是调用了SQLiteOpenHelper类的getWritableDatabase()函数和getReadableDatabase()函数这个两个函数会根据数据库是否存在、版本号和是否可写等情况,决定在返回数据库实例前,是否需要建立数据库,8.3数据库存储,8.3.3代码建库在代码第30行的close()函数中,调用了SQLiteDatabase实例的close()方法关闭数据库这是代码中唯一一处直接调用了SQLiteDatabase实例的方法SQLiteDatabase中也封装了打开数据库的函数openDatabases()和创建数据库函数openOrCreateDatabases(),因为代码中使用了帮助类SQLiteOpenHelper,从而避免直接调用SQLiteDatabase的打开和创建数据库的方法,简化了数据库打开过程中繁琐的逻辑判断过程,8.3数据库存储,8.3.3代码建库DBOpenHelper继承了帮助类SQLiteOpenHelper,重载了onCreate()函数和onUpgrade()函数,代码如下,8.3数据库存储,8.3.3代码建库,8.3数据库存储,8.3.3代码建库代码的第5行到第7行是创建表的SQL命令代码第10行和第15行分别重载了onCreate()函数和onUpgrade()函数,这是继承SQLiteOpenHelper类必须重载的两个函数onCreate()函数在数据库第一次建立时被调用,一般用来创建数据库中的表,并完成初始化工作在代码第11行中,通过调用SQLiteDatabase实例的execSQL()方法,执行创建表的SQL命令onUpgrade()函数在数据库需要升级时被调用,一般用来删除旧的数据库表,并将数据转移到新版本的数据库表中在代码第16行和第17行中,为了简单起见,并没有做任何数据转移,而仅仅删除原有的表后建立新的数据表,8.3数据库存储,8.3.3代码建库程序开发人员不应直接调用onCreate()和onUpgrade()函数,而应由SQLiteOpenHelper类来决定何时调用这两个函数SQLiteOpenHelper类的getWritableDatabase()函数和getReadableDatabase()函数是可以直接调用的函数getWritableDatabase()函数用来建立或打开可读写的数据库实例,一旦函数调用成功,数据库实例将被缓存,在需要使用数据库实例时就可以调用这个方法获取数据库实例,务必在不使用时调用close()函数关闭数据库如果保存数据库文件的磁盘空间已满,调用getWritableDatabase()函数则无法获得可读写的数据库实例,这时可以调用getReadableDatabase()函数,获得一个只读的数据库实例,8.3数据库存储,8.3.3代码建库如果不希望使用SQLiteOpenHelper类,也可以直接使用SQL命令建立数据库,方法是:先调用openOrCreateDatabases()函数创建数据库实例然后调用execSQL()函数执行SQL命令,完成数据库和数据表的建立过程,其示例代码如下,8.3数据库存储,8.3.4数据操作数据操作指的是对数据的添加、删除、查找和更新操作虽然程序开发人员完全可以通过执行SQL命名完成数据操作,但这里仍然推荐使用Android提供的专用类和方法,这些类和方法的使用更加简洁、方便为了使DBAdapter类支持数据添加、删除、更新和查找等功能,在DBAdapter类中增加下面的函数insert(Peoplepeople)用来添加一条数据queryAllData()用来获取全部数据queryOneData(longid)根据id获取一条数据deleteAllData()用来删除全部数据deleteOneData(longid)根据id删除一条数据updateOneData(longid,Peoplepeople)根据id更新一条数据,8.3数据库存储,8.3.4数据操作deleteAllData()用来删除全部数据deleteOneData(longid)根据id删除一条数据updateOneData(longid,Peoplepeople)根据id更新一条数据,8.3数据库存储,8.3.4数据操作ConvertToPeople(Cursorcursor)是私有函数,作用是将查询结果转换为自定义的People类实例People类包含四个公共属性,分别为ID、Name、Age和Height,对应数据库中的四个属性值重载toString()函数,主要是便于界面显示的需要People类的代码如下,8.3数据库存储,8.3.4数据操作,8.3数据库存储,8.3.4数据操作SQLiteDatabase类的公有函数insert()、delete()、update()和query(),封装了执行添加、删除、更新和查询功能的SQL命令下面分别介绍如何使用SQLiteDatabase类的公有函数,完成数据的添加、删除、更新和查询等操作,8.3数据库存储,8.3.4数据操作添加功能首先构造一个ContentValues实例,然后调用ContentValues实例的put()方法,将每个属性的值写入到ContentValues实例中,最后使用SQLiteDatabase实例的insert()函数,将ContentValues实例中的数据写入到指定的数据表中insert()函数的返回值是新数据插入的位置,即ID值。ContentValues类是一个数据承载容器,主要用来向数据库表中添加一条数据,8.3数据库存储,8.3.4数据操作第4行代码向ContentValues对象newValues中添加一个名称/值对,put()函数的第1个参数是名称,第2个参数是值在第8行代码的insert()函数中,第1个参数是数据表的名称,第2个参数是在NULL时的替换数据,第3个参数是需要向数据库表中添加的数据,8.3数据库存储,8.3.4数据操作删除功能删除数据比较简单,只需要调用当前数据库实例的delete()函数,并指明表名称和删除条件即可,8.3数据库存储,8.3.4数据操作删除功能delete()函数的第1个参数是数据表名称,第2个参数是删除条件在第2行代码中,删除条件为null,表示删除表中的所有数据代码第6行则指明需要删除数据的id值,因此deleteOneData()函数仅删除一条数据,此时delete()函数的返回值表示被删除的数据数量,8.3数据库存储,8.3.4数据操作更新功能更新数据同样要使用ContentValues实例,首先构造ContentValues实例,然后调用put()函数将属性值写入到ContentValues实例中,最后使用SQLiteDatabase的update()函数,并指定数据的更新条件,8.3数据库存储,8.3.4数据操作更新功能在代码的第7行中,update()函数的第1个参数表示数据表的名称,第2个参数是更新条件。update()函数的返回值表示数据库表中被更新的数据数量,8.3数据库存储,8.3.4数据操作查询功能介绍查询功能前,先要介绍一下Cursor类在Android系统中,数据库查询结果的返回值并不是数据集合的完整拷贝,而是返回数据集的指针,这个指针就是Cursor类Cursor类支持在查询结果的数据集合中以多种方式移动,并能够获取数据集合的属性名称和序号,具体的方法和说明可以参考下表,8.3数据库存储,8.3.4数据操作Cursor类的公有方法,8.3数据库存储,8.3.4数据操作从Cursor中提取数据可以参考ConvertToPeople()函数的实现方法在提取Cursor数据中的数据前,推荐测试Cursor中的数据数量,避免在数据获取中产生异常,例如下面代码的第3行到第5行从Cursor中提取数据使用类型安全的get()函数,函数的参数是属性的序号,为了获取属性的序号,可以使用getColumnIndex()函数获取指定属性的序号,8.3数据库存储,8.3.4数据操作,8.3数据库存储,8.3.4数据操作要进行数据查询就需要调用SQLiteDatabase类的query()函数,query()函数的语法如下Cursorandroid.database.sqlite.SQLiteDatabase.query(Stringtable,Stringcolumns,Stringselection,StringselectionArgs,StringgroupBy,Stringhaving,StringorderBy)query()函数的参数说明,8.3数据库存储,8.3.4数据操作根据id查询数据的代码,8.3数据库存储,8.3.4数据操作查询全部数据的代码,8.3数据库存储,8.3.4数据操作SQLiteDemo用户界面,8.3数据库存储,8.3.4数据操作SQLiteDemo是对SQLite数据库进行操作的示例在这个示例中,用户可以在界面的上方输入数据信息,通过“添加数据”按钮将数据写入数据库“全部显示”相当于查询数据库中的所有数据,并将数据显示在界面下方“清除显示”仅是清除界面下面显示数据,而不对数据库进行任何操作“全部删除”是数据库操作,将删除数据库中的所有数据在界面中部,以“ID+功能”命名的按钮,分别是根据ID删除数据、查询数据和更新数据,而这个ID值就取自本行的EditText控件,8.4数据分享,8.4.1ContentProviderAndroid应用程序运行在不同的进程空间中,因此不同应用程序的数据是不能够直接访问的为了增强程序之间的数据共享能力,Android系统提供了像SharedPreferences这类类简单的跨越程序边界的访问方法,但这些方法都存在一定的局限性ContentProvider(数据提供者)是应用程序之间共享数据的一种接口机制,是一种更为高级的数据共享方法,可以指定需要共享的数据,而其它应用程序则则可在不知道数据来源、路径的情况下,对共享数据进行查询、添加、删除和更新等操作,8.4数据分享,8.4.1ContentProvider在Android系统中,许多Android系统内置的数据也是通过ContentProvider提供给用户使用,例如通讯录、音视频文件和图像文件等在创建ContentProvider前,首先要实现底层的数据源,数据源包括数据库、文件系统或网络等,然后继承ContentProvider类中实现基本数据操作的接口函数,包括添加、删除、查找和更新等功能,8.4数据分享,8.4.1ContentProvider调用者不能直接调用ContentProvider的接口函数,而需要使用ContentResolver对象,通过URI间接调用ContentProvider,调用关系如下图所示,8.4数据分享,8.4.1ContentProvider在ContentResolver对象与ContentProvider进行交互时,通过URI确定要访问的ContentProvider数据集在发起一个请求的过程中,Android系统根据URI确定处理这个查询的ContentProvider,然后初始化ContentProvider所有需要的资源,这个初始化的工作是Android系统完成的,无需程序开发人员参与一般情况下只有一个ContentProvider对象,但却可以同时与多个ContentResolver进行交互,8.4数据分享,8.4.1ContentProviderContentProvider完全屏蔽了数据提供组件的数据存储方法在程序开发人员看来,数据提供者通过ContentProvider提供了一组标准的数据操作接口,但却无需知道数据提供者的内部数据的存储方法数据提供者可以使用SQLite数据库存储数据,也可以通过文件系统或SharedPreferences存储数据,甚至是使用网络存储的方法,这些数据的存储方法和存储设备对数据使用者都是不可见的同时,也正是这种屏蔽模式,很大程度上简化的ContentProvider的使用方法,使用者只要调用ContentProvider提供的接口函数,即可完成所有的数据操作,而数据存储方法则是ContentProvider设计者需要考虑的问题,8.4数据分享,8.4.1ContentProviderContentProvider的数据集类似于数据库的数据表,每行是一条记录,每列具有相同的数据类型如下表所示。每条记录都包含一个长型的字段_ID,用来唯一标识每条记录ContentProvider可以提供多个数据集,调用者使用URI对不同数据集的数据进行操作ContentProvider数据集,8.4数据分享,8.4.1ContentProviderURI是通用资源标志符(UniformResourceIdentifier),用来定位远程或本地的可用资源ContentProvider使用的URI语法结构如下1content:/content:/是通用前缀,表示该URI用于ContentProvider定位资源,无需修改是授权者名称,用来确定具体由哪一个ContentProvider提供资源因此,一般都由类的小写全称组成,以保证唯一性。是数据路径,用来确定请求的是哪个数据集,8.4数据分享,8.4.1ContentProvider如果ContentProvider仅提供一个数据集,数据路径则是可以省略的但如果ContentProvider提供多个数据集,数据路径则必须指明具体是哪一个数据集数据集的数据路径可以写成多段格式,例如people/girl和/people/boy。是数据编号,用来唯一确定数据集中的一条记录,用来匹配数据集中_ID字段的值如果请求的数据并不只限于一条数据,则是可以省略,例如请求整个people数据集的URI应写为1content:/edu.hrbeu.peopleprovider/people请求people数据集中第3条数据的URI则应写为1content:/edu.hrbeu.peopleprovider/people/3,8.4数据分享,8.4.2创建数据提供者程序开发人员通过继承ContentProvider类可以创建一个新的数据提供者,过程可以分为三步继承ContentProvider,并重载六个函数声明CONTENT_URI,实现UriMatcher注册ContentProvider,8.4数据分享,8.4.2创建数据提供者继承ContentProvider,并重载六个函数新建立的类继承ContentProvider后,共有六个函数需要重载,分别是delete():删除数据集insert():添加数据集qurey():查询数据集update():更新数据集onCreate():初始化底层数据集和建立数据连接等工作getType():返回指定URI的MIME数据类型如果URI是单条数据,则返回的MIME数据类型应以vnd.android.cursor.item开头如果URI是多条数据,则返回的MIME数据类型应以vnd.android.cursor.dir/开头,8.4数据分享,8.4.2创建数据提供者继承ContentProvider,并重载六个函数新建立的类继承ContentProvider后,Eclipse会提示程序开发人员需要重载部分的代码,并自动生成需要重载的代码框架下面的代码是Eclipse自动生成的代码框架,8.4数据分享,8.4.2创建数据提供者继承ContentProvider,并重载六个函数,8.4数据分享,8.4.2创建数据提供者继承ContentProvider,并重载六个函数,8.4数据分享,8.4.2创建数据提供者声明CONTENT_URI,实现UriMatcher在新构造的ContentProvider类中,经常需要判断URI是单条数据还是多条数据,最简单的方法是构造一个UriMatcher为了便于判断和使用URI,一般将URI的授权者名称和数据路径等内容声明为静态常量,并声明CONTENT_URI,8.4数据分享,8.4.2创建数据提供者声明CONTENT_URI和构造UriMatcher的代码如下,8.4数据分享,8.4.2创建数据提供者声明CONTENT_URI,实现UriMatcher第1行声明了URI的授权者名称第2行声明了单条数据的数据路径第3行声明了多条数据的数据路径第4行声明了CONTENT_URI的字符串形式第5行则正式声明了CONTENT_URI第6行声明了多条数据的返回代码第7行声明了单条数据的返回代码第9行声明了UriMatcher第10行到第13行的静态构造函数中,声明了UriMatcher的匹配方式和返回代码,8.4数据分享,8.4.2创建数据提供者声明CONTENT_URI,实现UriMatcher在第11行UriMatcher的构造函数中,UriMatcher.NO_MATCH是URI无匹配时的返回代码第12行的addURI()函数用来添加新的匹配项,语法如下1publicvoidaddURI(Stringauthority,Stringpath,intcode)authority表示匹配的授权者名称path表示数据路径#可以代表任何数字code表示返回代码,8.4数据分享,8.4.2创建数据提供者声明CONTENT_URI,实现UriMatcher使用UriMatcher时,则可以直接调用match()函数,对指定的URI进行判断,示例代码如下,8.4数据分享,8.4.2创建数据提供者注册ContentProvider在完成ContentProvider类的代码实现后,需要在AndroidManifest.xml文件中进行注册注册ContentProvider使用标签,示例代码如下124在上面的代码中,注册了一个授权者名称为edu.hrbeu.peopleprovider的ContentProvider,其实现类是PeopleProvider,8.4数据分享,8.4.3使用数据提供者使用ContentProvider并不需要直接调用类中的数据操作函数,而是通过Android组件都具有的ContentResolver对象,通过URI进行数据操作程序开发人员只需要知道URI和数据集的数据格式,则可以进行数据操作,解决不同应用程序之间的数据共享问题每个Android组件都具有一个ContentResolver对象,获取ContentResolver对象的方法是调用getContentResolver()函数,8.4数据分享,8.4.3使用数据提供者查询操作在获取到ContentResolver对象后,程序开发人员则可以使用query()函数查询目标数据下面的代码是查询ID为2的数据,8.4数据分享,8.4.3使用数据提供者查询操作从上面的代码不难看出
展开阅读全文
相关资源
相关搜索

当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!