Android五种数据存储⽅式
android 五种数据存储:SharePreferences、SQLite、Contert Provider、File、⽹络存储
Android系统提供了四种存储数据⽅式。分别为:SharePreference、SQLite、Content Provider和File。但由于Android系统中,数据基本是私有的,都是存放于”data/data”程序包名⽬录下,所以要实现数据共享,正确⽅式是使⽤Content Provider
SQLite:SQLite是⼀个轻量级的数据库,⽀持基本的SQL语法,是常被采⽤的⼀种数据存储⽅式。Android为此数据库提供了⼀个名为SQLiteDatabase的类,封装了⼀些操作数据库的api
SharedPreference:除SQLite数据库外,另⼀种常⽤的数据存储⽅式,其本质就是⼀个xml⽂件,常⽤于存储较简单的参数设置。
File:即常说的⽂件(I/O)存储⽅法,常⽤语存储⼤数量的数据,但是缺点是更新数据将是⼀件困难的事情。
ContentProvider: Android系统中能实现所有应⽤程序共享的⼀种数据存储⽅式,由于数据通常在各应⽤间的是互相私密的,所以此存储⽅式较少使⽤,但是其⼜是必不可少的⼀种存储⽅式。例如⾳频,视频,图⽚和通讯录,⼀般都可以采⽤此种⽅式进⾏存储。每个
Content Provider都会对外提供⼀个公共的URI(包装成Uri对象),如果应⽤程序有数据需要共享时,就需要使⽤Content Provider为这些数据定义⼀个URI,然后其他的应⽤程序就通过Content Provider传⼊这个URI来对数据进⾏操作。
URI由3个部分组成:"content://"、数据的路径、标识ID(可选)。
1)SQLite数据存储
======================================================================
SQLite是⼀种转为嵌⼊式设备设计的轻型数据库,其只有五种数据类型,分别为:
NULL:空值
INTEGER:整数
REAL:浮点数
TEXT:字符串
BLOB:⼤数据
在SQLite中,并没有专门设计BOOLEAN和DATE类型,因为BOOLEAN型可以⽤INTEGER的0和1代替true和false,⽽DATE类型则可以拥有特定格式的TEXT、REAL和INTEGER的值来代替显⽰,为了能⽅便的操作DATE类型,SQLite提供了⼀组函数,
在Android系统中提供了anroid.database.sqlite包,⽤于进⾏SQLite数据库的增,删,改,查⼯作,其主要⽅法如下:
 beginTransaction(): 开始⼀个事务。
 close(): 关闭连接,释放资源。
 delete(String table, String whereClause, String[] whereArgs): 根据给定条件,删除符合条件的记录。
 endTransaction(): 结束⼀个事务。
 execSQL(String sql): 执⾏给定SQL语句。
 insert(String table, String nullColumnHack, ContentValues values): 根据给定条件,插⼊⼀条记录。 
 openOrCreateDatabase(String path, SQLiteDatabase.CursorFactory factory): 根据给定条件连接数
据库,如果此数据库不存在,则创建。 query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy): 执⾏查询。
 rawQuery(String sql, String[] selectionArgs): 根据给定SQL,执⾏查询。
 update(String table, ContentValues values, String whereClause, String[] whereArgs): 根据给定条件,修改符合条件的记录。
  除了上诉主要⽅法外,Android还提供了诸多实⽤的⽅法,总之⼀句话:其实Android访问数据库是⼀件很⽅便的事⼉。
可以清晰的在查询结果中,红线上下的数据是完全⼀致的,也就是说query和rawQuery⽅法在的不同仅仅在于所需参数的不同。rawQuery⽅法需要开发者⼿动写出查询SQL,⽽query⽅法是由⽬标表名、where⼦句、order by⼦句、having⼦句等诸多⼦句由系统组成SQL语句。两⽅法同返回Cursor对象,所以两⽅在使⽤时孰优孰劣,就看具体情况了。本⼈更喜欢rawQuery的⽅式,因为此⽅式更接近传统Java开发,也可以由专业DBA来书写SQL语句,这样更符合MVC的思想,⽽且这样的代码可读性更⾼。(query⽅法⾥⾯参数实在太多,有点记不住谁是order by⼦句,谁是having⼦句了)
Cursor对象可以理解为游标对象,凡是对数据有所了解的⼈,相信对此对象都不会陌⽣,在这⾥机不再
累述。只提醒⼀点,在第⼀次读取Cursor对象中的数据时,⼀定要先移动游标,否则此游标的位置在第⼀条记录之前,会引发异常。
2.案例:
======================================================================
(2)SharedPreference数据存储
======================================================================
除了SQLite数据库外,SharedPreferences也是⼀种轻型的数据存储⽅式,它的本质是基于XML⽂件存储key-value键值对数据,通常⽤来存储⼀些简单的配置信息。其存储位置在/data/data/<;包名>/shared_prefs⽬录下。SharedPreferences对象本⾝只能获取数据⽽不⽀持存储和修改,存储修改是通过Editor对象实现。实现SharedPreferences存储的步骤如下:
  ⼀、根据Context获取SharedPreferences对象
  ⼆、利⽤edit()⽅法获取Editor对象。
  三、通过Editor对象存储key-value键值对数据。
四、通过commit()⽅法提交数据。
得到名为‘name’的偏好⽂件。同时你可以更改和返回他的值。任何调⽤者在调⽤同样名字的偏好⽂件时只有⼀个实例返回,这就意味着这些调⽤者都可以看到其他调⽤者做出的更改。
name为本组件的配置⽂件名( ⾃⼰定义,也就是⼀个⽂件名),当这个⽂件不存在时,直接创建,如果已经存在,则直接使⽤,
mode为操作模式,默认的模式为0或MODE_PRIVATE,还可以使⽤MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE mode指定为MODE_PRIVATE,则该配置⽂件只能被⾃⼰的应⽤程序访问。
mode指定为MODE_WORLD_READABLE,则该配置⽂件除了⾃⼰访问外还可以被其它应该程序读取。
mode指定为MODE_WORLD_WRITEABLE,则该配置⽂件除了⾃⼰访问外还可以被其它应该程序读取和写⼊
2,PreferenceManager的⽅法getSharedPreferences()
这个⽅法是⼀个普通的⽅法,必须有PreferenceManager的实例调⽤才⾏
这个⽅法是静态的,因此可以直接调⽤,同时它与我们调⽤getSharedPreferences()⽅法得到的返回值是⼀样的,只是调⽤的⽅式不同罢了。
因为SharedPreferences背后是使⽤xml⽂件保存数据,getSharedPreferences(name,mode)⽅法的第⼀个参数⽤于指定该⽂件的名称,名称不⽤带后缀,后缀会由Android⾃动加上。⽅法的第⼆个参数指定⽂件的操作模式,共有四种操作模式,这四种模式前⾯介绍使⽤⽂件⽅式保存数据时已经讲解过。如果希望SharedPreferences背后使⽤的xml⽂件能被其他应⽤读和写,可以指定
Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE权限。
另外Activity还提供了另⼀个getPreferences(mode)⽅法操作SharedPreferences,这个⽅法默认使⽤当前类不带包名的类名作为⽂件的名称。
如果访问其他应⽤中的Preference,前提条件是:该preference创建时指定了Context.MODE_WORLD_READABLE或者
Context.MODE_WORLD_WRITEABLE权限。如:有个<package name>为cn.yang.action的应⽤使⽤下⾯语句创建了preference。getSharedPreferences("TEST", Context.MODE_WORLD_READABLE);
其他应⽤要访问上⾯应⽤的preference,⾸先需要创建上⾯应⽤的Context,然后通过Context 访问preference ,访问preference时会在应⽤所在包下的shared_prefs⽬录到preference :
Context otherAppsContext = createPackageContext("cn.wsl.action", Context.CONTEXT_IGNORE_SECURITY); SharedPreferences sharedPreferences = SharedPreferences("TEST", Context.MODE_WORLD_READABLE); String name = String("name", "");
int age = Int("sex", "");
如果不通过创建Context访问其他应⽤的preference,也可以以读取xml⽂件⽅式直接访问其他应⽤preference对应的xml⽂件,如:
File xmlFile = new File(“/data/data/<package name>/shared_l”);//<package name>应替换成应⽤的包名。
具体实现代码如下:
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.main);
//获取SharedPreferences对象
Context ctx = MainActivity.this;
SharedPreferences sp = SharedPreferences("SI", MODE_PRIVATE);
//存⼊数据
Editor editor = sp.edit();//获取编辑器
editor.putString("STRING_KEY", "string1");
editor.putInt("INT_KEY", 0);
editor.putBoolean("BOOLEAN_KEY", true);
editormit();
//返回STRING_KEY的值
Log.d("SP", sp.getString("STRING_KEY", "none"));
//如果NOT_EXIST不存在,则返回值为"none"
Log.d("SP", sp.getString("NOT_EXIST", "none"));
editor记忆方法}
}
这段代码执⾏过后,即在/data/st/shared_prefs⽬录下⽣成了⼀个SI.xml⽂件,⼀个应⽤可以创建多个这样的xml⽂件。如图所⽰:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="STRING_KEY">string</string>
<int name="INT_KEY" value="0" />
<boolean name="BOOLEAN_KEY" value="true" />
</map>
在程序代码中,通过getXXX⽅法,可以⽅便的获得对应Key的Value值,如果key值错误或者此key⽆对应value值,SharedPreferences提供了⼀个赋予默认值的机会,以此保证程序的健壮性。如下图运⾏结果中因为并⽆值为"NOT_EXIST"的Key,所以Log打印出的是其默认
值:“none”。在访问⼀个不存在key值这个过程中,并⽆任何异常抛出。 
  SharedPreferences对象与SQLite数据库相⽐,免去了创建数据库,创建表,写SQL语句等诸多操作,相对⽽⾔更加⽅便,简洁。但是SharedPreferences也有其⾃⾝缺陷,⽐如其职能存储boolean,int,flo
at,long和String五种简单的数据类型,⽐如其⽆法进⾏条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储⽅式的⼀种补充,⽽⽆法完全替代如SQLite数据库这样的其他数据存储⽅式。
2.案例说明:
private void saveflag(int flag){
SharedPreferences SharedPreferences("scrolltag", Context.MODE_PRIVATE);
Editor editor=sp.edit();
editor.putInt("flagtag", flag);
editormit();
}
private int getflag(){
SharedPreferences sharedPreferences =getSharedPreferences("scrolltag", Context.MODE_PRIVATE);
int Int("flagtag", 0);
return flag;
}
//此⽅法可以在任何程序中添加该段代码,来获取cn.shine.hotel应⽤中的数据了,前提是在该应⽤⽣成xml⽂件的时候的权限应该
是 Context.MODE_WORLD_READABLE,或者是:读写
private String getScrollTextOther(){
String str=null;
Context otherAppsContext = null;
try {
otherAppsContext = createPackageContext("cn.shine.hotel",Context.CONTEXT_IGNORE_SECURITY);
SharedPreferences sp =SharedPreferences("scrolltext",Context.MODE_WORLD_READABLE);
String("scrolltext", "");
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return str;
}
======================================================================
(3)ContentProvider数据存储
======================================================================
ContentProvider是安卓平台中,在不同应⽤程序之间实现数据共享的⼀种机制。⼀个应⽤程序如果需要让别的程序可以操作⾃⼰的数据,即可采⽤这种机制。并且此种⽅式忽略了底层的数据存储实现,ContentProvider提供了⼀种统⼀的通过Uri实现数据操作的⽅式。其步骤为:
  1. 在当前应⽤程序中定义⼀个ContentProvider。
  2. 在当前应⽤程序的l中注册此ContentProvider
  3. 其他应⽤程序通过ContentResolver和Uri来获取此ContentProvider的数据。
 ContentResolver提供了诸如insert(), delete(), query()和update()之类的⽅法。⽤于实现对ContentProvider中数据的存取操作。
  Uri是⼀个通⽤资源标志符,将其分为A,B,C,D 4个部分:
    A:⽆法改变的标准前缀,包括;"content://"、"tel://"等。当前缀是"content://"时,说明通过⼀个Content Provider控制这些数据      B:URI的标识,它通过authorities属性声明,⽤于定义了是哪个ContentProvider提供这些数据。对于第三⽅应⽤程序,为了保证URI标识的唯⼀性,它必须是⼀个完整的、⼩写的类名。例如;"content://provider"
    C:路径,可以近似的理解为需要操作的数据库中表的名字,如:"content://yprovider/name"中的name
    D:如果URI中包含表⽰需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表⽰返回全部;
下⾯进⾏案展⽰:演⽰⼀下如何在应⽤程序之间相互获取数据:
在应⽤程序A中,继承ContentProvider类,并重写其中⽅法: