SharedPreferences存储数据
** 适用范围:**保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。比如应用程序的各种配置信息(如是否打开音效、是否使用震动效果、APP版本号等),解锁口 令密码等
核心原理:保存基于XML文件存储的key-value键值对数据,通常用来存储一些简单的配置信息。通过DDMS的File Explorer面板,展开文件浏览树,很明显SharedPreferences数据总是存储在/data/data//shared_prefs目录下。SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过SharedPreferences.edit()获取的内部接口Editor对象实现。
SharedPreferences本身是一 个接口,程序无法直接创建SharedPreferences实例,只能通过Context提供的getSharedPreferences(String name, int mode)方法来获取SharedPreferences实例,该方法中name表示要操作的xml文件名,第二个参数具体如下:
Context.MODE_PRIVATE: 指定该SharedPreferences数据只能被本应用程序读、写。
Context.MODE_WORLD_READABLE: 指定该SharedPreferences数据能被其他应用程序读,但不能写。
Context.MODE_WORLD_WRITEABLE: 指定该SharedPreferences数据能被其他应用程序读,写
Editor有如下主要重要方法:
SharedPreferences.Editor clear():清空SharedPreferences里所有数据
***SharedPreferences.Editor putXxx(String key , xxx value): ***向SharedPreferences存入指定key对应的数据,其中xxx 可以是boolean,float,int等各种基本类型据
***SharedPreferences.Editor remove(): ***删除SharedPreferences中指定key对应的数据项
*** boolean commit(): ***当Editor编辑完成后,使用该方法提交修改
实际案例:运行界面如下
这里只提供了两个按钮和一个输入文本框,布局简单,故在此不给出界面布局文件了,
**程序核心代码如下: **
classViewOclimplementsView.OnClickListener{@OverridepublicvoidonClick(View v){switch(v.getId()){caseR.id.btnSet://步骤1:获取输入值String code = txtCode.getText().toString().trim();//步骤2-1:创建一个SharedPreferences.Editor接口对象,lock表示要写入的XML文件名,MODE_WORLD_WRITEABLE写操作SharedPreferences.Editor editor = getSharedPreferences("lock", MODE_WORLD_WRITEABLE).edit();//步骤2-2:将获取过来的值放入文件editor.putString("code", code);//步骤3:提交editor.commit(); Toast.makeText(getApplicationContext(),"口令设置成功", Toast.LENGTH_LONG).show();break;caseR.id.btnGet://步骤1:创建一个SharedPreferences接口对象SharedPreferences read = getSharedPreferences("lock", MODE_WORLD_READABLE);//步骤2:获取文件中的值String value = read.getString("code",""); Toast.makeText(getApplicationContext(),"口令为:"+value, Toast.LENGTH_LONG).show();break; } } }
读写其他应用的SharedPreferences步骤如下:
1、在创建SharedPreferences时,指定MODE_WORLD_READABLE模式,表明该SharedPreferences数据可以被其他程序读取
2、创建其他应用程序对应的Context:
Context pvCount = createPackageContext("com.tony.app", Context.CONTEXT_IGNORE_SECURITY);这里的com.tony.app就是其他程序的包名
3、使用其他程序的Context获取对应的SharedPreferences
SharedPreferences read = pvCount**.**getSharedPreferences("lock", Context.MODE_WORLD_READABLE);
4、如果是写入数据,使用Editor接口即可,所有其他操作均和前面一致。
优缺点
优点
SharedPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。
缺点
SharedPreferences也有其自身缺陷,比如其只能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。
当存储的类型为对象时:
存
SharedPreferences.Editor editor = getSharedPreferences("lock",MODE_WORLD_WRITEABLE).edit();
editor.putString("list",new Gson().toJson(userInfoResponse.getData().getMedalList()));
editor.commit();
取
SharedPreferences read = getSharedPreferences("lock",MODE_WORLD_READABLE);
String list = read.getString("list","");
ArrayList returnList =new Gson().fromJson(list, new TypeToken>(){}.getType());
文件存储数据
核心原理: Context提供了两个方法来打开数据文件里的文件IO流 FileInputStream openFileInput(String name); FileOutputStream(String name , int mode),这两个方法第一个参数 用于指定文件名,第二个参数指定打开文件的模式。具体有以下值可选:
MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可 以使用Context.MODE_APPEND
MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;
MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。
除此之外,Context还提供了如下几个重要的方法:
getDir(String name , int mode):在应用程序的数据文件夹下获取或者创建name对应的子目录
File getFilesDir():获取该应用程序的数据文件夹得绝对路径
String[] fileList():返回该应用数据文件夹的全部文件
实际案例:界面沿用上图
核心代码如下:
private Stringread(){
try{
FileInputStream inputStream =this.openFileInput("message.txt");
byte[] buffer =new byte[1024];
int hasRead =0;
StringBuilder sb =new StringBuilder();
while ((hasRead = inputStream.read(buffer)) != -1){
sb.append(new String(buffer,0,hasRead));
}
inputStream.close();
return sb.toString();
}catch (Exception e){
e.printStackTrace();
}
return null;
}
private void write(String msg){
if (msg ==null)return;
try{
FileOutputStream fos = openFileOutput("message.txt",MODE_APPEND);
fos.write(msg.getBytes());
fos.close();
}catch (Exception e){
e.printStackTrace();
}
}
openFileOutput()方法的第一参数用于指定文件名称,不能包含路径分隔符“/” ,如果文件不存在,Android 会自动创建它。创建的文件保存在/data/data/
下面讲解某些特殊文件读写需要注意的地方:
读写sdcard上的文件
其中读写步骤按如下进行:
1、调用Environment的getExternalStorageState()方法判断手机上是否插了sd卡,且应用程序具有读写SD卡的权限,如下代码将返回true
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
Environment类中提供了几个静态常量用于标识外部存储的状态,这些状态都是String类型
MEDIA_BAD_REMOVAL 在没有挂载前存储媒体已经被移除。
MEDIA_CHECKING 正在检查存储媒体。
MEDIA_MOUNTED 存储媒体已经挂载,并且挂载点可读/写。
MEDIA_MOUNTED_READ_ONLY 存储媒体已经挂载,挂载点只读。
MEDIA_NOFS 存储媒体是空白或是不支持的文件系统。
MEDIA_REMOVED 存储媒体被移除。
MEDIA_SHARED 存储媒体正在通过USB共享。
MEDIA_UNMOUNTABLE 存储媒体无法挂载。
MEDIA_UNMOUNTED 存储媒体没有挂载
在Environment中还提供了Android标准目录的路径,以String类型提供。
DIRECTORY_ALARMS 系统提醒铃声存放的标准目录。
DIRECTORY_DCIM 相机拍摄照片和视频的标准目录。
DIRECTORY_DOWNLOADS 下载的标准目录。
DIRECTORY_MOVIES 电影存放的标准目录。
DIRECTORY_MUSIC 音乐存放的标准目录。
DIRECTORY_NOTIFICATIONS 系统通知铃声存放的标准目录。
DIRECTORY_PICTURES 图片存放的标准目录
DIRECTORY_PODCASTS 系统广播存放的标准目录。
DIRECTORY_RINGTONES 系统铃声存放的标准目录。
static File getDataDirectory() 获得data的目录(/data)。
static File getDownloadCacheDirectory() 获得下载缓存目录。(/cache)
static File getExternalStorageDirectory() 获得外部存储媒体目录。(/mnt/sdcard or /storage/sdcard0)
static File getRootDirectory() 获得系统主目录(/system)
除了用Environment获取存储目录之外,还可以通过把路径写死的方式,比如要读取外部存储/mnt/sdcard目录下的文件,可以在程序中直接用全路径,
但是这样做是很不好的,应该Android实在是太开放了,外部存储的目录的什么还是要固件制作商才知道,但是有一点是毋庸置疑的,就是Android框架层里面
已经是指定好了Environment.getDownloadCacheDirectory()的返回路径。所以,尽量用这种方式来获取和存储数据,以免固件厂商不同而造成路径的差异。
2、调用Environment.getExternalStorageDirectory()方法来获取外部存储器,也就是SD卡的目录,或者使用"/mnt/sdcard/"目录
3、使用IO流操作SD卡上的文件
注意点:手机应该已插入SD卡,对于模拟器而言,可通过mksdcard命令来创建虚拟存储卡
必须在AndroidManifest.xml上配置读写SD卡的权限
案例代码
:/**
* 文件写操作函数
*/
private void write(String content){
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){//判断挂载sd卡是否存在
File file =new File(Environment.getExternalStorageDirectory().toString()+File.separator
+dir+File.separator+fileName);//定义file对象
if (!file.getParentFile().exists()){//父文件夹不存在
file.getParentFile().mkdirs();//创建文件夹
}
PrintStream out =null;//打印流对象用于输出
try {
out =new PrintStream(new FileOutputStream(file,true));//追加文件
out.print(content);
}catch (Exception e){
e.printStackTrace();
}finally {
if (out !=null){
out.close();//关闭打印流
}
}
}else {
Toast.makeText(this, "保存失败,SD卡不存在!", Toast.LENGTH_LONG).show();
}
}
/**
* 文件读操作
*/
private Stringread(){
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
File file =new File(Environment.getExternalStorageDirectory().toString()+
File.separator+dir+File.separator+fileName);
if (!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
Scanner scanner =null;//扫描输入
StringBuilder sb =new StringBuilder();
try {
scanner =new Scanner(new FileInputStream(file));
while (scanner.hasNext()){//循环读取
sb.append(scanner.next()+"\n");
}
return sb.toString();
}catch (Exception e){
e.printStackTrace();
}finally {
if (scanner !=null){
scanner.close();
}
}
}
return null;
}
ContentProvider保存数据介绍
一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据完全暴露出去,而且ContentProvider是以类似数据库中表的方式将数据暴露的。那么外界获取其提供的数据,也就应该与从数据库中获取数据的操作基本一样,只不过是采用URL来表示外界需要访问的“数据库”。
ContentProvider提供了一种多应用间数据共享的方式。
ContentProvider是个实现了一组用于提供其他应用程序存取数据的标准方法的类。应用程序可以在ContentProvider中执行如下操作:查询数据、修改数据、添加数据、删除数据。
标准的ContentProvider:Android提供了一些已经在系统中实现的标准ContentProvider,比如联系人信息,图片库等等,可以用这些ContentProvider来访问设备上存储的联系人信息、图片等等。
在ContentProvider中使用的查询字符串有别于标准的SQL查询,很多诸如select、add、delete、modify等操作都使用一种特殊的URL进行,这种URL由3部分组成,“content://”,代表数据的路径和一个可选的表示数据的ID。
content://media/internal/images 这个URL将返回设备上存储的所有图片
content://contacts/people/ 这个URL将返回设备上的所有联系人信息
content://contacts/people/45 这个URL返回单个结果(联系人信息中ID为45的联系人记录)
如果想要存储字节型数据,比如位图文件等,那保存该数据的数据列其实是一个表示实际保存保存文件的URL字符串,客户端通过它来读取对应的文件数据,处理这种数据类型的ContentProvider需要实现一个名为_data的字段,_data字段列出了该文件在Android文件系统上的精确路径。这个字段不仅是供客户端使用,而且也可以供ContentResolver使用。客户端可以调用ContentResolver.openOutputStream()方法来处理该URL指向的文件资源,如果是ContentResolver本身的话,由于其持有的权限比客户端要高,所以它能直接访问该数据文件