Android的数据存储方案

1、概述

android中的数据是有权限控制的,应用软件数据为该应用软件所私有的。但是android也提供了一种标准的方式将软件的私有数据开放给其他应用软件。
android可供选择的存储方式:sharedPreferences、文件存储、SQLite数据库方式、内容提供器(Content provider)和网络存储。


2、sharedPreferences

sharedPreferences是一种轻量型的数据存储方式,本质上是基于XML文件存储key-value键值对数据,通常用来存储一些简单的配置信息。sharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过Editor对象实现的。(文件一般存放在/data/data/<包名>/shared_prefs目录下,只能在file explorer中看)
实现sharedPreferences存储的步骤为:
。根据Context获取sharedPreferences对象;
。利用edit()方法获取Editor对象(确保数据值是一致性的状态,并且控制所有的值都已经提交存储了);
。通过Editor对象存储key-value键值对数据;
。通过commit()方法提交数据
sharedPreferences比之于sqlLite数据库,免去了数据库方面的操作,更加的方便简洁。但是缺点就是只能存储boolean,int,float,long和String五种简单的数据类型,并且无法进行条件查询等。随意sharedPreferences只是一种补充方式。

private void doStore() {
   // get the object of SharedPreferences
   Context ctx = DataStoreActivity.this;
   SharedPreferences sp = ctx.getSharedPreferences("SP", MODE_PRIVATE);
   // store into values
   Editor editor = sp.edit();
   editor.putString("STRING_KEY", "string");        
   editor.putInt("INT_KEY", 0);
   editor.putBoolean("BOOLEAN_KEY", true);
   editor.commit();
   //read it	
   Log.d("SP", sp.getString("STRING_KEY", "none"));
   Log.d("SP", sp.getString("NOT_EXIST", "none"));
}


3、文件存储

android的文件操作和java中实现I/O的方式是类似的,其提供了openFileInput()和openFileOutput()方法来写入和读取设备上的文件。

FileOutputStream fos = ctx.openFileOutput("file_name", MODE_PRIVATE);  //写入
FileInputStream fis = ctx.openFileInput("file_name");  //读取

这两个方法只支持读取该应用目录下的文件,读取非自身目录下的文件将会抛出异常。不存在操作的文件,系统会在写入的时候自动创建(创建的文件一般保存在/data/data/<包名>/files目录下)。
默认情况下,使用openFileOutput方法创建的文件只能被其调用的应用使用,其他应用无法读取这个文件。如果需要在不同应用中的共享,可以使用Content Provider实现这个功能。

// 写入文件
FileOutputStream fos = openFileOutput("test", MODE_WORLD_READABLE);
fos.write(text.getText().toString().getBytes());

// 读取
FileInputStream fis = openFileInput("test");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = -1;
while ((length=fis.read(buffer)) != -1) {
	stream.write(buffer);
}
text.setText(stream.toString());

activity还提供了getCacheDir()和getFilesDir()方法:
。getCacheDir()方法用于获取/data/data/<package name>/cache目录
。getFilesDir()方法用于获取/data/data/<package name>/files目录

上面的操作都是将数据存储到手机内存或从手机内存读取数据,那怎么操作SD卡呢?

首先要在创建一张SDCard(镜像文件),创建SDCard可以再eclipse创建模拟器时同时创建,也可以使用dos命令【mksdcard -l mycard 20M F:\mysdcard.img】进行创建。
再就是需要为访问SDCard申请权限,如下:

<!-- 在SDCard中创建与删除文件权限 --> 
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> 

<!-- 往SDCard写入数据权限 --> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 

要往sdcard存放文件,程序必须先判断手机是否装有sdcard,并且可以进行读写。

if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ 
    File sdCardDir = Environment.getExternalStorageDirectory();//获取SDCard目录 
     File saveFile = new File(sdCardDir, “a.txt”); 
    FileOutputStream outStream = new FileOutputStream(saveFile);
    outStream.write("test".getBytes()); 
    outStream.close(); 
} 

Environment.getExternalStorageState():用于获取sdcard的状态,如果手机装有sdcard,并且可以进行读写,那么返回的状态就等于Environment.MEDIA_MOUNTED。
Environment.getExternalStorageDirectory():用于获取sdcard获取的目录,等价于:

File sdCardDir = new File("/sdcard"); //获取SDCard目录 


4、Environment类

String

MEDIA_BAD_REMOVAL

在没有挂载前存储媒体已经被移除。

String

MEDIA_CHECKING

正在检查存储媒体。

String

MEDIA_MOUNTED

存储媒体已经挂载,并且挂载点可读/写。

String

MEDIA_MOUNTED_READ_ONLY

存储媒体已经挂载,挂载点只读。

String

MEDIA_NOFS

存储媒体是空白或是不支持的文件系统。

String

MEDIA_REMOVED

存储媒体被移除。

String

MEDIA_SHARED

存储媒体正在通过USB共享。

String

MEDIA_UNMOUNTABLE

存储媒体无法挂载。

String

MEDIA_UNMOUNTED

存储媒体没有挂载。

static File

getDataDirectory()  获得android data的目录。

static File

getDownloadCacheDirectory()  获得下载缓存目录。

static File

getExternalStorageDirectory()  获得外部存储媒体目录。

static File

getExternalStoragePublicDirectory( String type)   Get a top-level public external storage directory for placing files of a particular type(根据文件的类别放到想要放到的地方).

static String

getExternalStorageState()  获得当前外部储存媒体的状态。

static File

getRootDirectory()   获得android的跟目录。

 

5、SQLLite存储方式

sqllite是一种轻型数据库,只支持五种数据类型,分别是:NULL(空值)、INTEGER(整数)、REAL(浮点数)、TEXT(字符串)、BLOB(大数据)。
1)创建数据库:openOrCreateDatabase(String path, SQLiteDatabase.CursorFactory factory) 根据给定条件连接数据库,如果此数据库不存在,则创建。

SQLiteDatabase db = this.openOrCreateDatabase("test_db.db", Context.MODE_PRIVATE, null);
SQLiteDatabase db2 = SQLiteDatabase.openOrCreateDatabase("/data/data/com.test/databases/test_db2.db3", null);

两种方式创建数据库,this.openOrCreateDatabase其实是根据SQLiteDatabase.openOrCreateDatabase而来的,SQLiteDatabase.openOrCreateDatabase()方法第一个参数要求输入绝对路径(所有的数据库都是存储在/data/data/<包名>/databases目录下);而采用this.openOrCreateDatabase()可以不用使用绝对路劲。

2)创建数据表:execSQL(String sql)— 执行给定SQL语句。

db.execSQL("create table tab(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)");

execSQL()可以之人任何的sql语句。

3)CUID:insert、delete、update、query(rawQuery)

db.insert(String table, String nullColumnHack, ContentValues values);  
db.update(String table, Contentvalues values, String whereClause, String whereArgs);  
db.delete(String table, String whereClause, String whereArgs);  

三个方法的第一个参数都是要进行操作的表名;
insert的第二个参数表示如果插入了一行空数据时,需要指定某一列的名称,系统将此列设置为NULL,否则会报错,第三个参数是ContentValues类型的变量,类似于键值对的Map,key代表列名,value代表值;
update的第二个ContentValues,更新该字段key为最新的value值,第三个参数whereClause表示WHERE表达式,比如"age > ? and age < ?”等,最后的whereArgs参数是占位符的实际参数值;
delete的参数和update是类似的;

db.rawQuery(String sql, String[] selectionArgs);  
db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy);  
db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);  
db.query(String distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit); 

上面几种都是常用的查询方法,第一种最为简单,将所有的SQL语句都组织到一个字符串中,使用占位符代替实际参数,selectionArgs就是占位符实际参数集;下面的几种参数都很类似,columns表示要查询的列所有名称集,selection表示WHERE之后的条件语句,可以使用占位符,groupBy指定分组的列名,having指定分组条件,配合groupBy使用,orderBy指定排序的列名,limit指定分页参数,distinct可以指定“true”或“false”表示要不要过滤重复值。需要注意的是,selection、groupBy、having、orderBy、limit这几个参数中不包括"WHERE”、"GROUP BY”、"HAVING”、"ORDER BY”、"LIMIT”等SQL关键字。

4)cursor操作

c.move(int offset); //以当前位置为参考,移动到指定行  
c.moveToFirst();    //移动到第一行  
c.moveToLast();     //移动到最后一行  
c.moveToPosition(int position); //移动到指定行  
c.moveToPrevious(); //移动到前一行  
c.moveToNext();     //移动到下一行  
c.isFirst();        //是否指向第一条  
c.isLast();     //是否指向最后一条  
c.isBeforeFirst();  //是否指向第一条之前  
c.isAfterLast();    //是否指向最后一条之后  
c.isNull(int columnIndex);  //指定列是否为空(列基数为0)  
c.isClosed();       //游标是否已关闭  
c.getCount();       //总数据项数  
c.getPosition();    //返回当前游标所指向的行数  
c.getColumnIndex(String columnName);//返回某列名对应的列索引值  
c.getString(int columnIndex);   //返回当前行指定列的值  


完整的实例:

protected void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);  
          
    //打开或创建test.db数据库  
     SQLiteDatabase db = openOrCreateDatabase("test.db", Context.MODE_PRIVATE, null);  
    db.execSQL("DROP TABLE IF EXISTS person");  
    //创建person表  
     db.execSQL("CREATE TABLE person (_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age SMALLINT)");  
    Person person = new Person();  
    person.name = "john";  
    person.age = 30;  
    //插入数据  
     db.execSQL("INSERT INTO person VALUES (NULL, ?, ?)", new Object[]{person.name, person.age});  
          
     person.name = "david";  
     person.age = 33;  
     //ContentValues以键值对的形式存放数据  
      ContentValues cv = new ContentValues();  
     cv.put("name", person.name);  
     cv.put("age", person.age);  
     //插入ContentValues中的数据  
      db.insert("person", null, cv);  
          
     cv = new ContentValues();  
     cv.put("age", 35);  
     //更新数据  
      db.update("person", cv, "name = ?", new String[]{"john"});  
          
     Cursor c = db.rawQuery("SELECT * FROM person WHERE age >= ?", new String[]{"33"});  
     while (c.moveToNext()) {  
        int _id = c.getInt(c.getColumnIndex("_id"));  
        String name = c.getString(c.getColumnIndex("name"));  
        int age = c.getInt(c.getColumnIndex("age"));  
        Log.i("db", "_id=>" + _id + ", name=>" + name + ", age=>" + age);  
     }  
        c.close();  
          
     //删除数据  
      db.delete("person", "age < ?", new String[]{"35"});  
          
     //关闭当前数据库  
      db.close();  
          
     //删除test.db数据库  
     deleteDatabase("test.db");  
}  


6、SQLiteOpenHelper

帮助管理数据库的创建和版本的管理。要使用它必须实现它的onCreate(SQLiteDatabase),onUpgrade(SQLiteDatabase, int, int)方法。
onCreate:当数据库第一次被建立的时候被执行;
onUpgrade:当数据库需要被更新的时候执行,如数据库版本的变更;
还可以根据实际情况实现onOpen()等方法。

7、ContentProvider

android系统的数据时私有的,包括文件数据和数据库数据,两个程序之间无法进行数据的交换。ContentProvider实现了一组标准的方法接口,从而能够让其他的应用保存或读取此Content Provider的各种数据类型。就是说,一个程序可以通过实现一个Content Provider的抽象接口将自己的数据暴露出去,外部可以访问。步骤为:
1)在当前应用程序中实现一个Content Provider
2)在当前应用程序的AndroidManifest.xml中注册此Content Provider
3)其他程序通过ContentResolver和Uri来获取此Content Provider的数据


3、Handler

Handler主要负责发送和处理消息,用途:
。按计划发送消息或执行某个线程;
。从其他线程中发送来的消息放入消息队列中,避免线程冲突;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值