1、Android数据存储与IO,第8章,2018/10/11,1,Android 中的数据存储技术,手机作为特殊的移动存储设备,可以携带多种数据。例如:音频、视频、图片、通讯录,也包含应用程序私有数据,比如游戏进度、通关成绩等。 Android中提供了多种方式用于保存持久数据。这些方式的选择依赖于应用程序的需要,例如数据是应用程序独享还是可以被其他应用程序或者用户访问、数据存储空间的大小。,2018/10/11,2,Android 中的数据存储技术,Android有三种存储数据的方式: SharePreference:轻量级键-值方式存储,以XML文件方式保存。 文件:采用java.io.*库所
2、提供的I/O接口读写文件。 SQLit数据库:SQLite是轻量级嵌入式内置数据库。,2018/10/11,3,1. 简单存储,什么是SharePreferences? 问题一:用手机播放器播放音乐,我们希望重启播放器时,播放器能从上次停止的那首曲目开始播放,如何实现? 类似于我们常用的ini文件,用来保存应用程序的一些属性设置,常用于存储较简单的参数设置。 例如:用于保存上一次用户所作的修改或者自定义参数设定,当再次启动程序后依然保持原有的设置。如设置的手机开机问候语。,2018/10/11,4,1. 简单存储(P306),SharePreferences SharedPreferences
3、是一种轻量级的数据保存方式 通过SharedPreferences可以将NVP(Name/Value Pair,名称/值对)保存在Android的文件系统中,而且SharedPreferences完全屏蔽了对文件系统的操作过程 开发人员通过调用SharedPreferences对NVP进行保存和读取。,2018/10/11,5,1. 简单存储,SharedPreferences不仅能够保存数据,还能够实现不同应用程序间的数据共享 SharedPreferences支持三种访问模式 私有(Context.MODE_PRIVATE):数据只能被本应用程序读写 全局读(Context.MODE_WO
4、RLD_READABLE):数据能被其他应用程序读,但不能写 全局写(Context.MODE_WORLD_WRITEABLE):数据能被其他应用程序写,但不能读,2018/10/11,6,1. 简单存储,获取SharedPreferences对象步骤: (1)定义SharedPreferences的访问模式; 下面的代码将访问模式定义为私有模式有时候需要将SharedPreferences的访问模式设定为既可以全局读,也可以全局写,这样就需要将两种模式写成下面的方式:,2018/10/11,7,1 简单存储,获取SharedPreferences对象步骤: (2)定义SharedPrefer
5、ences的名称,这个名称与在Android文件系统保存的文件同名。因此,具有相同的SharedPreferences 名称的NVP内容,都会保存在同一个文件中。(3)将访问模式和SharedPreferences名称作为参数,传递到getSharedPreferences()函数,并获取到SharedPreferences对象,2018/10/11,9,1 简单存储,写入数据: 利用前面获取的SharedPreferences对象的edit()方法获得它对应的Editor对象; 利用Editor对象提供的putXXX方法写入数据 调用Editor对象的commit()方法提交修改 Share
6、dPreferences广泛支持各种基本数据类型,包括整型、布尔型、浮点型和长型等等,1 简单存储,从已经保存的SharedPreferences中读取数据: 调用getSharedPreferences()函数,并在函数的第1个参数中指明需要访问的SharedPreferences名称 通过getXXX()函数获取保存在SharedPreferences中的NVPgetXXX()函数的第1个参数是NVP的名称 第2个参数是在无法获取到数值的时候使用的缺省值,1 简单存储,Example:08_SimplePreferenceDemo 用户在界面上输入的信息,通过SharedPreferenc
7、es在进行保存。 保存在SharedPreferences的信息可以被读取出来,并重新呈现在用户界面上。,2018/10/11,12,1 简单存储,我们已经知道了用Preferences来存取数据,那么这些数据究竟被保存在什么地方了呢? 其实,每安装一个应用程序时,SharedPreferences文件就保存在/data/data/shared_prefs目录下,其中的文件就是我们的数据:,2018/10/11,13,1 简单存储,在Linux系统中,文件权限分别描述了创建者、同组用户和其他用户对文件的操作限制。 x表示可执行,r表示可读,w表示可写,d表示目录,-表示普通文件。 因此,“-r
8、w-rw-rw”表示xml文件可以被创建者、同组用户和其他用户进行读取和写入操作,但不可执行 产生这样的文件权限与程序人员设定的SharedPreferences的访问模式有关,“-rw-rw-rw”的权限是“全局读+全局写”的结果 如果将SharedPreferences的访问模式设置为私有,则文件权限将成为“-rw-rw -”,表示仅有创建者和同组用户具有读写文件的权限。,1 简单存储,dateStore.xml文件是以XML格式保存的信息,内容如图如下:,789 ssm ,1 简单存储,访问其他应用程序的SharedPreferences必须满足三个条件: 共享者将SharedPrefe
9、rences的访问模式设置为全局读或全局写; 访问者知道共享者的包名称和SharedPreferences的名称 通过Context获得SharedPreferences对象; 访问者确切知道每个数据的名称和数据类型,2018/10/11,16,2018/10/11,17,2 文件存储,Android使用的是基于Linux的文件系统,程序开发人员可以建立和访问程序自身的私有文件,也可以访问保存在资源目录中的原始文件和XML文件,还可以在SD卡等外部存储设备中保存文件。,2018/10/11,18,2 文件存储内部存储(P404),Android系统允许应用程序创建仅能够自身访问的私有文件,文件
10、保存在设备的内部存储器上,在Linux系统下的/data/data/files目录中Android系统支持标准Java的IO流体系 FileInputStream类 FileOutputStream类 Context提供了能够简化读写流式文件过程的函数 openFileOutput():打开文件输入流 openFileInput():打开文件输出流,2018/10/11,19,2 文件存储内部存储,openFileOutput()函数 openFileOutput()函数用于写入数据。如果指定的文件不存在,则创建一个新的文件。 openFileOutput()函数的语法格式如下第1个参数是文件
11、名称,这个参数不可以包含描述路径的斜杠 第2个参数是操作模式 函数的返回值是FileOutputStream类型(字节流),2 文件存储-内部存储,Android系统支持四种文件操作模式,2 文件存储-内部存储,使用openFileOutput()函数建立新文件的示例代码如下第1行代码定义了建立文件的名称fileDemo.txt 第2行代码使用openFileOutput()函数以私有模式建立文件 第4行代码调用write()函数将数据写入文件 第5行代码调用flush()函数将所有剩余的数据写入文件 第6行代码调用close()函数关闭FileOutputStream,2 文件存储-内部存储
12、,openFileOutput()函数 为了提高文件系统的性能,一般调用write()函数时,如果写入的数据量较小,系统会把数据保存在数据缓冲区中,等数据量累积到一定程度时再一次性的写入文件中 flush()函数,可以将缓冲区内所有的数据写入文件 文件操作结束后,用close()关闭文件。,2018/10/11,23,2 文件存储-内部存储,openFileInput()函数 openFileInput()函数用于打开一个与应用程序联系的私有文件输入流; 当文件不存在时抛出FileNotFoundException 异常; openFileInput()函数的语法格式如下:第1个参数也是文件名
13、称,同样不允许包含描述路径的斜杠,2018/10/11,24,2 文件存储-内部存储,使用openFileInput ()函数打开已有文件的示例代码如下上面的两部分代码在实际使用过程中会遇到错误提示,因为文件操作可能会遇到各种问题而最终导致操作失败,因此代码应该使用try/catch捕获可能产生的异常,2 文件存储-内部存储,Example:DataStoreCh08 用户界面如图。程序运行后,在 /data/data/com.example.datastorech08/files/目录下,找到了新建立的file1.txt文件,2018/10/11,26,要求: 1.以用户指定文件名传递给Fi
14、leIOActivity 2.如果文件存在读取文件内容,并显示 3.修改内容后,点击“保存修改”,存储文件内容指定文件中。,2 文件存储-内部存储,gh.txt从文件权限上进行分析,“-rw-rw-”表明文件仅允许文件创建者和同组用户读写,其他用户无权使用 文件的大小为5个字节,2018/10/11,27,2 文件存储外部存储,Android的外部存储设备指的是SD卡(Secure Digital Memory Card),是一种广泛使用于数码设备上的记忆卡 不是所有的Android手机都有SD卡,但Android系统提供了对SD卡的便捷的访问方法,2018/10/11,28,2 文件存储外部
15、存储,SD卡适用于保存大尺寸的文件或者是一些无需设置访问权限的文件,可以保存录制的大容量的视频文件和音频文件等; SD卡使用的是FAT(File Allocation Table)的文件系统,不支持访问模式和权限控制,但可以通过Linux文件系统的文件访问权限的控制保证文件的私密性; Android模拟器支持SD卡。,2 文件存储外部存储,2018/10/11,30,2 文件存储外部存储,编程访问SD卡 首先需要检测系统的/mnt/sdcard目录是否可用 如果不可用,则说明设备中的SD卡已经被移除,在Android模拟器则表明SD卡映像没有被正确加载 如果可用,则直接通过使用标准的Java.
16、io.File类进行访问 FileInputStream FileOutputStream FileReader FileWriter,2. 文件存储外部存储,将数据保存在SD卡 如果文件存在,则打开SD卡中文件,并读取 用户改写文件内容,点”保存修改”进行保存,将两个按钮功能进行合并 准备好文件名(包括路径) 通过Intent 向FileIOActivity传递 FileIOActivity中对传到的文件名,统一以下处理 fin = new FileInputStream(filename); fout = new FileOutputStream(filename);,2018/10/11
17、,32,3. SQLite数据库,SQLite是一个开源的嵌入式关系数据库,在2000年由D. Richard Hipp发布 SQLite数据库特点 更加适用于嵌入式系统,嵌入到使用它的应用程序中 占用非常少,运行高效可靠,可移植性好 提供了零配置(zero-configuration)运行模式 SQLite数据库不仅提高了运行效率,而且屏蔽了数据库使用和管理的复杂性,程序仅需要进行最基本的数据操作,其他操作可以交给进程内部的数据库引擎完成,2018/10/11,33,3. SQLite数据库,手动建库 手动建立数据库指的是使用sqlite3工具,通过手工输入命令行完成数据库的建立过程 sql
18、ite3是SQLite数据库自带的一个基于命令行的SQL命令执行工具,并可以显示命令执行结果 sqlite3工具被集成在Android系统中,用户在Linux的命令行界面中输入sqlite3可启动,并得到工具的版本信息,如下面的代码所示。 启动Linux的命令行界面的方法是在CMD中输入adb shell命令,3. SQLite数据库,手动建库 在启动sqlite3工具后,提示符从“#”变为“sqlite”,表示命令行界面进入与SQLite数据库的交互模式,此时可以输入命令建立、删除或修改数据库的内容 正确退出sqlite3工具的方法是使用.exit命令 原则上,每个应用程序的数据库都保存在各
19、自的/data/data/ /databases目录下。如果使用手工方式建立数据库,则必须手工建立数据库目录,目前版本无须修改数据库目录的权限,3. SQLite数据库,手动建库 在SQLite数据库中,每个数据库保存在一个独立的文件中,使用sqlite3工具后加文件名的方式打开数据库文件,如果指定文件不存在,sqlite3工具则自动创建新文件 下面的代码将创建名为people的数据库,在文件系统中将产生一个名为people.db的数据库文件,3. SQLite数据库,手动建库 下面的代码在新创建的数据库中,构造了一个名为peopleinfo的表,使用create table命令,关系模式为p
20、eopleinfo ( _id, name, room, fee) 包含四个属性,_id是整型的主键;name表示姓名,字符型,不可以为空值;room表示宿舍号,整数型;fee表示学费,浮点型,3. SQLite数据库,手动建库 为了确认数据表是否创建成功,可以使用.tables命令,显示当前数据库中的所有表。从下面的代码中可以观察到,当前数据库仅有一个名为peopleinfo的表 当然,也可以使用.schema命令查看建立表时使用的SQL命令。如果当前数据库中包含多个表,则可以使用.schema 表名的形式,显示指定表的建立命令,3. SQLite数据库,手动建库 向表中添加数据,使用ins
21、ert into values命令代码运行成功后,数据库的peopleinfo表将有数据存在。因为_id是自增加的主键,因此在输入null后,SQLite数据库会自动填写该项的内容,3. SQLite数据库,手动建库 在数据添加完毕后,使用select命令,显示指定数据表中的所有数据信息,命令格式为select 属性 from 表名 下面的代码用来显示peopleinfo表的所有数据,3. SQLite数据库,手动建库 上面的查询结果看起来不是非常直观,可以使用mode命令将结果输出格式更改为“表格”方式,3. SQLite数据库,手动建库 更新数据可以使用update命令,命令格式为upda
22、te 表名 set 属性=“新值” where 条件 更新数据后,同样使用select命令显示数据,则可以确定数据是否正确更新 下面的代码将姓名为Jack数据中的宿舍号更新为203,3. SQLite数据库,手动建库 删除数据可以使用delete命令,命令格式为delete from 表名where 条件 下面的代码将_id为4数据从表peopleinfo中删除,手动建库后的使用方法,1.要指定数据库文件的版本号2.要把库文件权限修改为rw-rw-rwChmod 666 people.db,2018/10/11,44,3. SQLite数据库,通过SQLiteDatabase对象管理、操作数据
23、库 通过以下静态方法获取SQLiteDatabase对象(P414) openDatabase openOrCreateDatabase 或者使用SQLiteOpenHelper获取SQLiteDatabase对象 使用SQLiteDatabase对象的方法操作数据库 execSQL:执行SQL语句(可以带参数) rawQuery:执行带占位符的SQL查询,返回Cursor对象 Example:SqliteExample 使用SQL语言完成对数据库的操作,2018/10/11,45,3. SQLite数据库,SQLiteOpenHelper使用方法: 创建SQLiteOpenHelper的子类
24、 重写其两个抽象方法 onCreate方法:用于初次使用软件时生成数据表,初始化表数据等; onUpgrade方法:用于升级软件时更新数据库表结构,2018/10/11,46,3. SQLite数据库,SQLiteOpenHelper:管理数据库的工具类,可用于管理数据库的创建和更新(P422) 包含如下常用方法:,2018/10/11,47,用于打开数据库连接,用于关闭数据库连接,3. SQLite数据库,查询功能 在Android系统中,数据库查询结果的返回值并不是数据集合的完整拷贝,而是返回数据集的指针,这个指针就是Cursor类 Cursor类支持在查询的数据集合中多种方式移动,并能够
25、获取数据集合的属性名称和序号,2018/10/11,48,3. SQLite数据库,Cursor类的方法和说明,2018/10/11,49,3. SQLite数据库,查询功能 cursor = helper.getReadableDatabase().rawQuery( “select * from peopleinfo“, null); 在提取Cursor数据中的数据前,推荐测试Cursor中的数据数量,避免在数据获取中产生异常。从Cursor中提取数据,使用类型安全的get()函数,函数的输入值为属性的序号,为了获取属性的序号,可以使用getColumnIndex()函数获取指定属性的序号
26、。,2018/10/11,50,if (cursor.moveToNext() index = cursor.getPosition();for (int i = 0; i 4; i+)infoi.setText(cursor.getString(i);,3. SQLite数据库,删除记录的SQL语句参考语句 helper.getReadableDatabase().execSQL( “delete from peopleinfo where _id=?“, new Stringinfo0.getText().toString();,2018/10/11,51,注意:数据库中数据更改后,已有的
27、Cursor对象中的值不会更新,3. SQLite数据库,更新记录的SQL语句参考语句 String values = new String4; for (int i = 1; i 4; i+) valuesi - 1 = infoi.getText().toString(); values3 = info0.getText().toString(); helper.getReadableDatabase() .execSQL( “update peopleinfo set name=?,room=?,fee=? where _id=?“,values);,2018/10/11,52,3. S
28、QLite数据库,新增记录的SQL语句参考语句 String args = new String3; for (int i = 1; i 4; i+)argsi - 1 = infoi.getText().toString(); helper.getReadableDatabase().execSQL( “insert into peopleinfo values(null,?,?,?)“, args);,2018/10/11,53,4. 手势检测(P427),GestureDetector类:手势检测器 OnGestureListener接口:监听器,负责对用户的手势行为提供响应 onFling()方法:当用户在触摸屏上拖过时触发该方法 ViewFlipper组件:容器类组件 调用addView方法添加多个组件 通过setInAnimation和setOutAnimation方法设置各个组件间切换时的动画效果 showPrevious和showNext方法在多个组件之间切换,2018/10/11,54,