前言,好吧,这部分,没那么多要说的,其实,就是运用。主要是,毕竟客户端,存储并非重点。不过,还是要了解和学习的
先来补充一点基础尝试吧:(免得以后,听到别人聊起,自己一脸蒙蔽)
ADT:Android 开发工具
API:应用程序编程接口
IDE:集成开发环境
JDK:Java 开发工具包
JSON:JavaScript 对象表示法
SDK:软件开发工具包
SQL:结构化查询语言
UI:用户界面
XML:可扩展标记语言
ok,回到正题,本文,主要讲的是数据存储,主要是以系统讲解为主,因为,如果只是运用的话,大可百度,一大堆文章可以看,一大堆框架可以用。顺便说一下:我写的自我提升系列,都是属于系统的介绍某个东西,深入介绍会在后面的其他系列中写。
原本是打算从一个例子出发的,不过,后来想了一想,这个问题,还是留给读者自己去想吧,不然,读者都不会思考了。下面就简单介绍一下常用的存储方式吧,这里,将会单纯的从技术层面去介绍。
SharedPreferences
这玩意,算是这些存储中最简单的方式了吧,不过,还是有一些细节需要知道,不然,也容易出错的
简单介绍
SharePreferences是用来存储一些简单配置信息的一种机制,使用Map数据结构来存储数据,以键值对的方式存储,采用了XML格式将数据存储到设备中,只能在同一个包内使用,不能在不同的包之间使用,其实也就是说只能在创建它的应用中使用,其他应用无法使用。(这里顺便说一下,在libary引入的情况下,也是可以使用的,不过,顺序是,引用者和自己可以使用,其他不可以使用)
创建的存储文件保存在/data/data//shares_prefs文件夹下。
创建文件的模式
Context.MODE_PRIVATE(个人建议,用这种模式)
默认操作模式,表示xml存储文件是私有的,只能在创建文件的应用中访问(如果其他应用和创建该文件的应用具有相同的uid,也可以直接访问)。
Context.MODE_WORLD_WREADABLE(不建议使用)
开放读模式,表示允许其他应用进程具备对该文件的读权限。官方文档不建议使用该模式,因为这为导致严重的安全漏洞。
Context.MODE_WORLD_WRITABLE(不建议使用)
开放写模式,表示允许其他应用进程具备堆该文件的写权限,原因同上一条
Context.MODE_APPEND(个人不建议使用,嫌麻烦)
追加模式,和openFileOutput一起使用。该模式下如果文件存在,就往文件末尾进行追加,否则创建新文件。
简单使用
通过Context.getSharedPreferences方法获取SharedPreferences对象,参数分别为存储的文件名和存储模式。
获取SharedPreferences对象
SharedPreferences sp = getSharedPreferences(DATABASE, Activity.MODE_PRIVATE);
获取Editor对象
Editor editor = sp.edit();
插入数据
调用Editor.putxxxx方法,两个参数分别为键和值。(注意,这里put要指明类型,比如putSting(?,?))
获取数据:
调用Editor.getxxxx方法,两个参数分别为键和不存在指定键时的默认值。
删除数据:
调用Editor.remove方法,参数为指定的键。
清空所有数据:
调用Editor.clear方法
上述所有方法调用都要执行Editor.commit方法来提交,例子:editor.putString("hello",hello).commit.
个人封装方法(由于,常规的写法,个人觉得,要去写key,后面用的时候,也要写key,感觉很烦,所以就把key集成在了名字里面)
我的包结构吧,名字应该很形象吧。多的就不说,继续往下看。
这个BaseSp的左右,就是初始化sp,我这里,举例,就只写了String的api。其他的是一个意思的。
这里的BasePrefItem是父类item,这其中,简单的用到了泛型,因为,我并不知道我要存什么类型的key value。
这里是具体的item,当然,是以String为例的,多的不想解释,代码很明显了。
这里是具体的sp了,继承basesp,写入文件名,然后,就是创建各个类型的item,一次写好,一辈子不愁的思想。
使用,简单吧,经过我前面的封装,使用,永远是一句话,而且,看名字就明了了吧,不用再去找一个类,专门放各种常量了吧,这种写法,唯一比较大的类,就是上面的AppSP这个类了,不过,通常,我会根据业务,或者数据模型,去写不同的实现类 SP。
需要注意一点:SP是线程不安全的,所以,在同步,多线程里面,最好不要用SP。
SQLite数据库
这玩意,说实话,我在项目中,用得比较少,讲真,在这个时代,网络才是王道(客户端而言)。不过,也得学,不是
SQLite 介绍
SQLite 一个非常流行的嵌入式数据库,它支持 SQL 语言,并且只利用很少的内存就有很好的性能。此外它还是开源的,任何人都可以使用它。许多开源项目((Mozilla, PHP, Python)都使用了 SQLite.
SQLite 由以下几个组件组成:SQL 编译器、内核、后端以及附件。SQLite 通过利用虚拟机和虚拟数据库引擎(VDBE),使调试、修改和扩展 SQLite 的内核变得更加方便。为了解释,在网上找的简易版示意图。
SQLite 基本上符合 SQL-92 标准,和其他的主要 SQL 数据库没什么区别。它的优点就是高效,Android 运行时环境包含了完整的 SQLite。
SQLite 和其他数据库最大的不同就是对数据类型的支持,创建一个表时,可以在 CREATE TABLE 语句中指定某列的数据类型,但是你可以把任何数据类型放入任何列中。当某个值插入数据库时,SQLite 将检查它的类型。如果该类型与关联的列不匹配,则 SQLite 会尝试将该值转换成该列的类型。如果不能转换,则该值将作为其本身具有的类型存储。比如可以把一个字符串(String)放入 INTEGER 列。SQLite 称这为“弱类型”(manifest typing.)。
此外,SQLite 不支持一些标准的 SQL 功能,特别是外键约束(FOREIGN KEY constrains),嵌套 transcaction 和 RIGHT OUTER JOIN 和 FULL OUTER JOIN, 还有一些 ALTER TABLE 功能。(这其实也是sqlite的鸡肋之处)
除了上述功能外,SQLite 是一个完整的 SQL 系统,拥有完整的触发器,交易等等。(小但强大)
Android 集成了 SQLite 数据库
Android 在运行时(run-time)集成了 SQLite,所以每个 Android 应用程序都可以使用 SQLite 数据库。对于熟悉 SQL 的开发人员来时,在 Android 开发中使用 SQLite 相当简单。但是,由于 JDBC 会消耗太多的系统资源,所以 JDBC 对于手机这种内存受限设备来说并不合适。因此,Android 提供了一些新的 API 来使用 SQLite 数据库,Android 开发中,我们需要学使用这些 API。
数据库存储在 data/< 项目文件夹 >/databases/ 下。
Android 开发中使用 SQLite 数据库
关于这个数据库的问题,个人而言实在是没多少可以说的,毕竟对sqlite的使用比较少,不想误导大家,所有,就请大家自行百度,sqlite语法了吧。
不过,先提出几个理念:数据库的一行,相当于,java中的一个对象。所以,在Android中,使用sqlite,一般都是,把对象存为一个表,这个表中只有一行最新的唯一数据,而使用的时候,通常也是取出一行,赋值给一个对象,然后,操作对象。
这一部分,算是写得有点水了吧,不过,没法。见谅了。顺带说一句,本来,是想好好说一下关于数据库更新的问题,不过发现,数据更新是个麻烦事儿,特别是涉及到跨版本升级的问题。这里,就不多说了,只是提一句。
Internal Storage 和 External Storage
简单介绍(Internal Storage 其实就是我们说的私有数据,External Storage简单说,就是sdcard,简单可以这么粗暴的理解)
Internal Storage 和 External Storage 的区别
Internal storage 是属于应用程序的,文件管理器看不见。(私有)
External storage 在文件浏览器里是可以看见的 /mnt 。(共有)
这两个概念都是相对于应用来说的,应该理解为逻辑上的概念,不应理解为物理上的外部SD卡和手机或移动设备内存.。
一个应用把数据存在external storage上时,那么数据成为共有的,所有人都可见的和可用的。
存在internal storage上时,只有这个应用本身可以看到和使用。
很多没有插SD卡的设备,系统会虚拟出一部分存储空间用来做公共存储(主要是音乐,文档之类的media)。
所以:如果是私密性,安全性的文件数据,就存Internal Storage,如果是大家共用的就存External Storage(ps:在高手面前,这两个都是可以被查看的,只是相对于软件本身是安全的,私密的)
Internal Storage 把数据存储在设备内部存储器上,存储在/data/data//files目录下。
默认情况下在这里存储的数据为应用程序的私有数据,其它应用程序不能访问。
卸载应用程序后,内部存储器的/data/data/目录及其下子目录和文件一同被删除。
ok,下面再详细,分别介绍,这二者是怎么使用的:
Internal Storage使用介绍
存数据(也可以叫写数据,其实正规叫法是写数据,不过,方便理解,就交存数据)
1. 调用openFileOutput(String fileName, int mode)方法,
若fileName对应的文件存在,就打开该文件,若不存在,并以mode权限创建该文件并打开,该方法
返回一个指向fileName对应文件的FileOutputStream,使用这个FileOutputStream可向文件中写入数据。
2. 调用FileOutputStream对象的write()方法向文件中写入数据。
3. 调用FileOutputStream对象的close()方法关闭文件写入流。
例:向内部存储器中写入一个名为"abc.txt"的文件后,会在内部存储器的/data/data//files/目录下生成"abc.txt"文件。
1,2,3步对应上图。login就是我们所存的文件,文件中我们存如了username和password。
取数据(也叫读数据)
1. 调用openFileInputStream(String fileName)方法打开内部存储器中fileName对应的文件,若该文件存在,该方法
返回一个指向fileName文件的FileInputStream对象。
2. 调用FileInputStream对象的read()方法读取fileName文件中的内容。
3. 调用FileInputStream对象的close()方法关闭文件读取流。
如上图,经过读取数据之后,会把读出来的字符放到buffer中,然后,我们就可以从buffer中,拿出我们要的string了。
ok,内部存储的知识,就介绍到这里,不过,这个内部存储有一个软肋,就是软件被卸载,他就没有了,这点和sp其实差不多,所以,当我们需要保存一些数据,达到,就算软件卸载了,再安装也能使用的效果时,就需要用到接下来要用的东西了,外部存储。
External Storage 简单介绍即使用
简单介绍
它并非始终可用,因为用户可采用 USB 存储设备的形式装载外部存储,并在某些情况下会从设备中将其移除。
它是全局可读的,因此此处保存的文件可能不受您控制地被读取。
当用户卸载您的应用时,保存在Environment.getExternalStoragePublicDirectory()目录里的文件不会被删除,保存在getExternalFilesDir()或getExternalCacheDir()目录里的文件会被删除
对于无需访问限制以及您希望与其他应用共享或允许用户使用计算机访问的文件,外部存储是最佳位置。
如果您的应用需要只需读取外部存储,需在清单文件申请android.permission.READ_EXTERNAL_STORAGE权限
如果您的应用需要写入(隐含读取)外部存储,只需在清单文件申请android.permission.WRITE_EXTERNAL_STORAGE权限
通常,是两个权限都申请
存数据:(写入)
1 通过Environment类的getExternalStorageState()方法来判断手机是否有SDcard:
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
2.获取SD卡的目录
File file = Environment.getExternalStorageDirectory();
3.创建文件,或者在原文件中添加数据
FileOutputStream fileW =newFileOutputStream(file.getCanonicalPath() +"/test.txt");
fileW.write(str.getBytes());
4.关流
fileW.close();
细心的同学,应该会注意到,这里的filew.close为什么不是写在finaly里面呢?好吧,的确应该写在finaly里面的,或许又有发现,怎么在存数据的最后没有清空缓存呢?好吧,其实也应该那么做的,所以,最正确的写法,应该是在写入数据之后,清空缓存,然后在finaly里面close。
那么,我为什么不这么写呢?因为我以前就是这么写的,但是,也没有出错。不过,最好还是严谨一点吧。
取数据:(读出)
1.判断sd卡是否存在,获取sd卡目录
2.获取文件,判断文件是否存在(这里其实,就是先假设文件存在,获取文件)
3.打开文件输入流
4.把读出来的数据,添加到buffer
5.遍历buffer,转换成string
ok,外部存储,基本就是这样了。
小结
这一篇文章写的时间,相对比较长,主要写得合适,不能太复杂,也不能太简单。其实,本问中,对于数据的地方,真心想写,但也不敢写,这部分,说简单,也简单,说难也难。所以,干脆就简单介绍一下。本文主要介绍了Android本地存储的一些基本东西,不过,说实在的,就app而言的话,这部分,个人觉得不是特别重要(但是,还是重要的,只是程度没有网络,线程,效果那些重要,当然,难度,也相对较低),但是,如果走比较深入的话,那就另当别论了。比如,数据库的版本更新,数据结构的设计等等。不然怎么有专门的数据库架构师。