android 数据存储与访问

很多时候我们的软件需要对处理后的数据进行存储或再次访问。Android为数据存储提供了如下几种方式:
(1)文件
(2)SharedPreferences(参数)
(3)SQLite数据库

(4)内容提供者(Content provider)


1.使用文件进行存储和访问

Java提供了一套完整的IO流体系,这些IO可以非常方便的访问各种文件内容,同样,Android也支持这种方式进行访问

Context提供了两种方式来打开应用程序文件的IO流  openFileInput(String name)、openFileOutput(String name ,int mode)

(1)openFIleInput

FileInputStream inStream = this.getContext().openFileInput(FILE_NAME);
Log.i("FileTest", readInStream(inStream));
readInStream方法

public String readInStream(FileInputStream inStream){
	try {
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int length = -1;
		while((length = inStream.read(buffer)) != -1 ){
			outStream.write(buffer, 0, length);
		}
		outStream.close();
		inStream.close();
		return outStream.toString();
	} catch (IOException e) {
		Log.i("FileTest", e.getMessage());
	}
	return null;
}

注意:对于私有文件只能被创建该文件的应用访问,如果希望文件能被其他应用读和写,可以在创建文件时,指定Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE权限。

(2)openFileOutput(String name ,int mode)

    openFileOutput()方法的第一参数用于指定文件名称,不能包含路径分隔符“/” ,如果文件不存在,Android 会自动创建它。创建的文件保存在/data/data/<package name>/files目录;第二参数用于指定操作模式,有四种模式,分别为: 

Context.MODE_PRIVATE    =  0         为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容。
Context.MODE_APPEND    =  32768     会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
Context.MODE_WORLD_READABLE =  1     表示当前文件可以被其他应用读取。
Context.MODE_WORLD_WRITEABLE =  2     表示当前文件可以被其他应用写入。

         FileOutputStream outStream = this.openFileOutput("test.txt", Context.MODE_PRIVATE);
         outStream.write("测试".getBytes());
         outStream.close();   

当程序通过Context提供了两种方式  openFileInput(String name)和openFileOutput(String name ,int mode)打开时,程序打开的都是应用程序文件夹得文件,这样存储的大小有限制,因此,android提供了应用程序读写SD卡的方法

  读写Sd卡文件的步骤如下:

(1)调用Environment的getExternalStorageState方法判断手机上是否有SD卡,并且可以读写

  注意:在程序中访问SDCard,你需要申请访问SDCard的权限。
在AndroidManifest.xml中加入访问SDCard的权限如下:
<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)

(2)调用Environment.getExternalStorageDirectory()方法用于获取SDCard的目录

(3)使用FileInputStream、FileOutputStream、FileReader和FileWriter等读写SD卡的文件

2.使用SharedPreferences(参数)进行存储和访问

  Android平台给我们提供了一个SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。使用SharedPreferences保存数据,其背后是用xml文件存放数据的,文件存放在/data/data/<package name>/shared_prefs目录下。
(1)存储
SharedPreferences sharedPreferences = getSharedPreferences("test", Context.MODE_PRIVATE);
Editor editor = sharedPreferences.edit();//获取编辑器
editor.putString("name", "gzsll");
editor.putInt("age", 20);
editor.commit();//提交修改
生成的test.xml文档如下
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="name">gzsll</string>
<int name="age" value="20" />
</map>
下面一一介绍这些方法和参数
(1)getSharedPreferences(name,mode)方法的第一个参数用于指定该文件的名称,名称不用带后缀,后缀会由Android自动加上。方法的第二个参数指定文件的操作模式,共有四种操作模式,这四种模式和openFileOutput的四种模式一样。
(2)Editor editor = sharedPreferences.edit();//获取编辑器   使用Editor对SharedPreferences写入数据
  Editor提供以下方法:
  clear()  :清空所有数据
  putXXX(String key,XXX value)  :存入指定key的值
  remove(String key)  : 移除指定key
  commit() : 提交修改
  
(2)访问SharedPreferences中的数据
SharedPreferences sharedPreferences = getSharedPreferences("test", Context.MODE_PRIVATE);
//getString()第二个参数为缺省值,如果preference中不存在该key,将返回缺省值
String name = sharedPreferences.getString("name", "");
int age = sharedPreferences.getInt("age", 1);

(3)读取其他应用程序
  如果访问其他应用中的Preference,前提条件是:该preference创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE权限。然后创建其他程序的Context  
Context otherAppsContext = createPackageContext("com.gzsll.io", Context.CONTEXT_IGNORE_SECURITY);
com.gzsll.io就是其他程序的包名

3.使用SQLite数据库进行数据存储和访问

  在Android平台上,集成了一个嵌入式关系型数据库—SQLite,SQLite3支持 NULL、INTEGER、REAL(浮点数字)、TEXT(字符串文本)和BLOB(二进制对象)数据类型,虽然它支持的类型只有五种,但实际上sqlite3也接受varchar(n)、char(n)、decimal(p,s) 等数据类型,只不过在运算或保存时会转成对应的五种数据类型。 SQLite最大的特点是你可以把各种类型的数据保存到任何字段中,而不用关心字段声明的数据类型是什么。 SQLite可以解析大部分标准SQL语句,允许开发者使用SQL语句操作数据库
(1)使用SQLiteDatabase操作SQLite数据库
  Android提供了一个名为SQLiteDatabase的类,该类封装了一些操作数据库的API,使用该类可以完成对数据库的CRUD操作
  SQLiteDatabase提供了以下方法来打开数据库
  

  获取SQLiteDatabase对象后就可以使用对应的方法操作数据库,这里重点掌握execSQL()和rawQuery()方法。 execSQL()方法可以执行insert、delete、update和CREATE TABLE之类有更改行为的SQL语句; rawQuery()方法用于执行select语句。
execSQL()方法的使用例子:
SQLiteDatabase db = ....;
db.execSQL("insert into person(name, age) values('gzsll', 20)");
db.close();
还可以使用占位符?
SQLiteDatabase db = ....;
db.execSQL("insert into person(name, age) values(?,?)", new Object[]{"gzsll", 20}); 
db.close();

SQLiteDatabase的rawQuery() 用于执行select语句,使用例子如下:
        Cursor cursor = db.rawQuery("select * from person where name=?",new String[] { name });
	if (cursor.moveToFirst()) {
	  int index = cursor.getColumnIndex("phone"); // 得到phone在表中是第几列
	  String phone = cursor.getString(index);
	  Log.i(TAG, "phone =" + phone);
	 }
	// 记得关闭掉 cursor
	cursor.close();
	result = false;
        // 释放数据库的链接
	db.close();
  Cursor是结果集游标,用于对结果集进行随机访问,如果大家熟悉jdbc, 其实Cursor与JDBC中的ResultSet作用很相似。使用moveToNext()方法可以将游标从当前行移动到下一行,如果已经移过了结果集的最后一行,返回结果为false,否则为true。另外Cursor 还有常用的moveToPrevious()方法(用于将游标从当前行移动到上一行,如果已经移过了结果集的第一行,返回值为false,否则为true )、moveToFirst()方法(用于将游标移动到结果集的第一行,如果结果集为空,返回值为false,否则为true )和moveToLast()方法(用于将游标移动到结果集的最后一行,如果结果集为空,返回值为false,否则为true ) 。

(2)使用SQLiteOpenHelper对数据库进行管理
  SQLiteOpenHelper可以用于数据库的创建和版本更新
 
public class MyDBHelper extends SQLiteOpenHelper {	
	private static final String CREATE_SQL="create table Mydict(_id integer primary key autoincrement,word varchar(50),detail varchar(255))";
	public MyDBHelper(Context context, String name,
			int version) {
		super(context, name, null, version);
		// TODO Auto-generated constructor stub
	}
	@Override
	public void onCreate(SQLiteDatabase db) {
		// TODO Auto-generated method stub
		db.execSQL(CREATE_SQL);
	}
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		// TODO Auto-generated method stub
		
	}	
	
}
一旦得到SQLiteOpenHelper对象后,就无需使用SQLiteDatabase的静态方法创建数据库了,而是调用getWritableDatabase()或getReadableDatabase()方法获取数据库
dbHelper.getWritableDatabase().execSQL("insert into Mydict values(null,?,?)",new String[]{word,detail});

(3)使用事务
 
使用SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction() 方法时会检查事务的标志是否为成功,如果程序执行到endTransaction()之前调用了setTransactionSuccessful() 方法设置事务的标志为成功则提交事务,如果没有调用setTransactionSuccessful() 方法则回滚事务。使用例子如下: 
SQLiteDatabase db = ....;
db.beginTransaction();//开始事务
try {
    db.execSQL("insert into person(name, age) values(?,?)", new Object[]{"gzsll", 20});
    db.execSQL("update person set name=? where personid=?", new Object[]{"sll", 1});
    db.setTransactionSuccessful();//调用此方法会在执行到endTransaction() 时提交当前事务,如果不调用此方法会回滚事务
} finally {
    db.endTransaction();//由事务的标志决定是提交事务,还是回滚事务
} 
db.close(); 
上面两条SQL语句在同一个事务中执行。

4.使用内容提供者(Content provider)共享

  为了在不同程序之间共享数据,我们可以使用好几种方法,但是,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一,如:采用xml文件对外共享数据,需要进行xml解析才能读取数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读取数据。因此,Android提供了ContentProvider对外共享数据,它统一了数据的访问方式。
  开发ContentProvider的步骤如下:
 (1)定义自己的ContentProvider类,该类需要继承ContentProvider基类,并重写以下方法
public class DictProvider extends ContentProvider{
   public boolean onCreate() 该方法在ContentProvider创建后就会被调用, Android开机后, ContentProvider在其它应用第一次访问它时才会被创建
   public Uri insert(Uri uri, ContentValues values)  该方法用于供外部应用往ContentProvider添加数据。
   public int delete(Uri uri, String selection, String[] selectionArgs)  该方法用于供外部应用从ContentProvider删除数据。
   public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 该方法用于供外部应用更新ContentProvider中的数据。
   public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)  该方法用于供外部应用从ContentProvider中获取数据。
   public String getType(Uri uri)}  该方法用于返回当前Url所代表数据的MIME类型。如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头.



 (2)需要在AndroidManifest.xml使用<provider>对该ContentProvider进行配置,为了能让其他应用找到该ContentProvider , ContentProvider 采用了authorities对它进行唯一标识
<provider android:name=".DictProvider" android:authorities="com.gzsll.provider.dictprovider"/>

 uri简介

 Uri代表了要操作的数据,Uri主要包含了两部分信息:1》需要操作的ContentProvider ,2》对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:

 content://com.gzsll.provider.dictprovider/word/10   

  content://    : Android所规定的scheme

  com.gzsll.provider.dictprovider        Authority用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它

  word/10        路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定      10代表word下面id为10的数据

  要操作xxx表中的记录,可以构建这样的路径:/xxx
  当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:
  要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
  如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:
  Uri uri = Uri.parse("content://com.gzsll.provider.dictprovider/word/10 ")

  因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 

  UriMatcher类用于匹配Uri  ;ContentUris类用于获取Uri路径后面的ID部分

使用ContentResolver操作ContentProvider中的数据

当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver 类提供了与ContentProvider类相同签名的四个方法:
public Uri insert(Uri uri, ContentValues values)
该方法用于往ContentProvider添加数据。
public int delete(Uri uri, String selection, String[] selectionArgs)
该方法用于从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
该方法用于更新ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
该方法用于从ContentProvider中获取数据。

监听ContentProvider中数据的变化

如果ContentProvider的访问者需要知道ContentProvider中的数据发生了变化,可以在ContentProvider 发生数据变化时调用getContentResolver().notifyChange(uri, null)来通知注册在此URI上的访问者,如果ContentProvider的访问者需要得到数据变化通知,必须使用ContentObserver对数据(数据采用uri描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserver的onChange()方法。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值