所有的App都可以说是与数据打交道的,离开数据它们什么都不是.那么平时我们怎么存储一些关键的数据呢?
1 持久化技术简介
数据持久化就是指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或电脑关机的情况下,这些数据仍然不会丢失。保存在内存中的数据是处于瞬时状态的,而保存在存储设备中的数据是处于持久状态的,持久化技术则是提供了一种机制可以让数据在瞬时状态和持久状态之间进行转换。
Android系统中主要提供了三种方式用于简单地实现数据持久化功能,即文件存储、SharedPreference存储以及数据库存储。当然,除了这三种方式之外,你还可以将数据保存在手机的SD卡中,不过使用文件、SharedPreference或数据库来保存数据会相对更简单一些,而且比起将数据保存在SD卡中会更加的安全。
2 文件存储
文件存储是Android中最基本的一种数据存储方式,它不对存储的内容进行任何的格式化处理,所有数据都是原封不动地保存到文件当中的,因而它比较适合用于存储一些简单的文本数据或二进制数据.
2.1 将数据存储到文件中
Context类中提供了一个openFileOutput ()方法,可以用于将数据存储到指定的文件中。
openFileOutput ()方法返回的是一个FileOutputStream对象,得到了这个对象之后就可以使用Java流的方式将数据写入到文件中了.
BufferedWriter writernewnew"data", Context.MODE_PRIVATE)));
writer.write(data);
那么我们来创建一个实际的例子,使用openFileOutput()来进行数据存储.
S1:在activity_main.xml中创建一个EditText控件
S2:在MainActivity.java中运用openFileOutput()方法保存数据
S3:运行项目并查看
2.2 从文件中读取数据
将数据存储到文件中,Context类中还提供了一个openFileInput()方法,用于从文件中读取数据.
例子程序:
3 SharedPreferences存储
不同于文件储存方式,SharedPreferences采用键值对的方式进行存储.也就是说,但保存或获取一个数据,必须同时提供这个数据的Key值.
并且,SharedPreferences可以保存不同类类型的数据,如果保存的是整数,那么取出的就是整数;如果保存的是String字符串,那么取出的也是字符串.
具体的用法下面会详述.
3.1 将数据存储到SharedPreferences中
要使用SharedPreferences保存数据就必须在程序中获得SharedPreferences.这个对象有三种方式获取:
1)Context类中的的getSharedPreferences()方法:这个参数会传入两个参数,SharedPreferences的文件名和操作模式.如果传入的文件名不存在,则会在/data/data/<packagename>/shared_prefs/目录下;操作模式有两种,MODE_PRIVATE和MODE_MULTI_PROCESS.MODE_PRIVATE指的是只有当前程序才能对该文件进行读取,MODE_MULTI_PROCESS一般用于多个进程对这个文件进行访问.(MULTI 许多)
2)Activity类中的getPreferences()方法:与上面这个方法比,这个方法只接受一个参数,就是操作模式的参数.文件名默认为当前活动的类名.
3)PreferenceManager类中的getDefaultSharedPreferences()方法:这是一个静态方法,它接受一个Context参数.并默认使用当前活动的包名作为前缀来命名SharedPreferences文件
得到SharedPreferences对象后,就可以向SharedPreferences文件进行数据存储了.存储的步骤分为三步:
S1:调用SharedPreferences对象的edit()方法来获取一个SharedPrefences.Editor对象
S2:用SharedPrefences.Editor对象的putXxx()方法,向Editor对象中添加数据
S3:调用commit()方法,提交并存储数据
例子程序:
activity_main.xml
MainActivity.java
我们看看实际效果:
实际上他是以XML文件进行存储的
3.2 从SharedPreferences中读取数据
直接上代码说明使用方法:
S1:在activity_main.xml文件中新建一个Button
S2:在MainActivity.java中书写这个Button的点击事件
3.3 实现记住密码功能
S1:实现一个lauout:Login.xml
S2:创建LoginActivity.java
S3:在AndroidMainfest.xml中注册Login.xml和activity_main.xml文件
S4:运行程序
4 SQLite数据库存储
Android OS中行有个DB---SQLite数据库.Android中的SQLite数据库到底是如何使用的呢?
4.1 创建数据库
Android为了让我们能够更加方便地管理数据库,专门提供了一个SQLiteOpenHelper帮助类,借助这个类就可以非常简单地对数据库进行创建和升级;
1) SQLiteOpenHelper是一个抽象类.如果我们想要使用它的话,就需要创建一个自己的帮助类去继承它。
2) SQLiteOpenHelper中有两个抽象方法,分别是onCreate()和onUpgrade(),我们必须在自己的帮助类里面重写这两个方法,然后分别在这两个方法中去实现创建、升级数据库的逻辑.
3) SQLiteOpenHelper中还有两个非常重要的实例方法,getReadableDatabase()和getWritableDatabase()。这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则创建一个新的数据库),并返回一个可对数据库进行读写操作的对象
4) SQLiteOpenHelper中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可。这个构造方法中接收四个参数,第一个参数是Context,这个没什么好说的,必须要有它才能对数据库进行操作。第二个参数是数据库名,创建数据库时使用的就是这里指定的名称。第三个参数允许我们在查询数据的时候返回一个自定义的Cursor,一般都是传入null。第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作。构建出SQLiteOpenHelper的实例之后,再调用它的getReadableDatabase()或getWritableDatabase()方法就能够创建数据库了,数据库文件会存放在/data/data/<package name>/databases/目录下。此时,重写的onCreate()方法也会得到执行,所以通常会在这里去处理一些创建表的逻辑。
实例:
S1:创建继承SQLiteOpenHelper的实现类MyDatabaseHelper,并重写onCreate()方法
S2:在MainActivity.java中调用getWritableDatabase()方法
验证下数据库是否生成:
4.2 升级数据库
考虑一个情况,现在我们的数据库中已经有一张记录各个书的详细信息表Book,现在我们需要添加一张用户记录书籍分类的表Category,那么该怎么做呢?
创建Category表的语句为:
create table Category (
id integer primary key autoincrement,
category_name text,
category_code integer)
这个需求是不是直接在MyDatabaseHelper.java中加入上述Create语句,并在onCreate()方法中调用呢?
当然不是!
其实没有创建成功的原因不难思考,因为此时BookStore.db数据库已经存在了,之后不管我们怎样点击Create database按钮,MyDatabaseHelper中的onCreate()方法都不会再次执行,因此新添加的表也就无法得到创建了。
解决方案就是在上面的基础上修改onUpgrade()方法:
注意,这个时候在MainActivity.java中,调用MyDatabaseHelper的构造方法时输入的第四个参数要有所不同:
4.3 添加数据
见面介绍的是创建和升级数据库,下面的部分我们着重介绍对数据库的CRUD操作(C的操作前面已经介绍)
考虑到开发者的水平总是参差不齐(是否能够熟练的使用SQL语句),Android OS提供了一些列辅助方法-----在Android中即使不使用SQL语句,也能轻松的完成CRUD操作.
我们晓得的是,嗲用SQLiteOpenHelper的getReadableDatabase()或者getWritableDatabase()方法是可以创建/升级数据库的,且这两个方法还会返回一个SQLiteDatabase对象,借助这个对象我们可以对数据进行CRUD操作,具体看Android的API文档.
添加操作主要使用SQLiteDatabase的insert()方法,这个方法就是专门用于添加数据的。它接收三个参数,第一个参数是表名,我们希望向哪张表里添加数据,这里就传入该表的名字。第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值NULL,一般我们用不到这个功能,直接传入null即可。第三个参数是一个ContentValues对象,它提供了一系列的put()方法重载,用于向ContentValues中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可.
例子程序:
S1:在布局文件中添加一个按钮
S2:修改MainActivity中的代码
最后的结果为:
4.4 更新数据
SQLiteDatabase中也是提供了一个非常好用的update()方法用于对数据进行更新,这个方法接收四个参数,第一个参数和insert()方法一样,也是表名,在这里指定去更新哪张表里的数据。第二个参数是ContentValues对象,要把更新数据在这里组装进去。第三、第四个参数用于去约束更新某一行或某几行中的数据,不指定的话默认就是更新所有行。
例子程序:
S1:在布局文件中添加一个按钮
S2:修改MainActivity中的代码
最后的结果:
4.5 删除数据
SQLiteDatabase中提供了一个delete()方法专门用于删除数据,这个方法接收三个参数,第一个参数仍然是表名,这个已经没什么好说的了,第二、第三个参数又是用于去约束删除某一行或某几行的数据,不指定的话默认就是删除所有行
例子程序:
S1:在布局文件中添加一个按钮
S2:修改MainActivity中的代码
结果:
4.6 查询数据
数据查询也是CRUD操作中最难的一部分.(科普下,SQL的全称是Structured Query Language,结构化查询语言,所以它的大部分功能体现在"查"上)本小节只会介绍Android的查询.
SQLiteDatabase有一个query()的方法进行数据查询.这个方法十分复杂,它有4个重载方法:
我们这里介绍个参数最少的方法,它有7个参数!
这里我们写一个最简单的例子,其他的看Android 的 API去.
4.7 使用SQL操作数据库
Android 的SQLite数据库也可以直接使用SQL语言进行操作上述所有过程
方法如下:
添加数据的方法如下:
db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)",new String[] { "The Da Vinci Code", "Dan Brown", "454", "16.96" });
db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)",new String[] { "The Lost Symbol", "Dan Brown", "510", "19.95" });
更新数据的方法如下:
db.execSQL("update Book set price = ? where name = ?", new String[] { "10.99", "The Da Vinci Code" });
删除数据的方法如下:
db.execSQL("delete from Book where pages > ?", new String[] { "500" });
查询数据的方法如下:
db.rawQuery("select * from Book", null);
5 SQLite数据库的最佳实践
这里我们简单的介绍SQLite数据的两个进阶技巧
5.1 使用事务
数据库是有事务的概念的,那么在Android的SQLite中如何实现事务呢?
比如,现在Book表里面的数据已经很老了,我们需要全部删除后添加一些新的数据.这个操作我们需要在一个事务中完成,如何操作呢?
S1:添加一个按钮,用于触发替换数据操作,id定义为replace_data
S2:在这个按钮的触发事件中加入事务
5.2 升级数据库的最佳写法
回忆下我们前面的升级数据库的操作,其实特别的不妥----我们为了保证数据库是最新的,我们只是在onUpgrade()方法中删除掉所有的表,然后再重新执行下onCreate()方法----这种方法实在不妥,每次的升级会删除前面所有操作的表中的数据,这对应用程序是不允许的.
回忆下我们创建数据库对象DataHelper时,传入的参数中最后一个代表数据库版本.我们可以这么做,比较传入的版本号与现有数据库的的版本号的差异,然后分别执行"差异的部分",做相应的改变.
A) 第一版程序:只需创建一张Book表,那么MyDatabaseHelper的代码如下:
B)几周后,我们有了新的需求:需要向数据库中添加一张Category表,于是我们这么修改代码:
这样修改代码的好处是,当用户直接安装版本二的时候会执行onCreate()方法创建数据库;当用户由版本一升级到版本二时,只会创建Category表,原来的Book表不会产生任何变化.
C)没过多久,新的需求又来了!这次需要个Book表和Category表建立关联(在Book表中新增一个category_id的字段),代码修改如下:
但是!请特别注意,B和C的代码有个严重的错误(细节)需要注意.先抛出结论,在onUpgrade()方法里,switch中每一个case后面建议不要加break关键字.
这是为什么呢?
如果用户由版本一直接升级到版本三,那么实际(如果加break关键字)DB只会升级到版本二!
6 小结与点评
本章主要是对Android常用的数据持久化方式进行了详细的讲解,包括文件存储、SharedPreferences存储以及数据库存储。其中文件适用于存储一些简单的文本数据或者二进制数据,SharedPreferences适用于存储一些键值对,而数据库则适用于存储那些复杂的关系型数据。