Android开发存储方式详解

一、SharedPreferences

        SharedPreferences是一种轻型数据存储方式,本质是基于XML文件存储key-value键值对数据,通常用来存储一些简单的匹配信息。

        SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过Editor对象实现。实现SharedPreferences存储的步骤如下:
1、获取SharedPreferences对象
2、获取SharedPreferences.Editor对象
3、通过Editor接口的putXxx方法保存key-value对,其中Xxx表示不同的数据类型。
4、通过Editor接口的commit方法保存key-value对。

//生成默认的SharedPreferences
//SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
//自己定义(文件名称,权限)
SharedPreferences pref = getSharedPreferences("myPref", MODE_PRIVATE);
//通过Editor写入
Editor editor = pref.edit();
editor.putString("name", "张三");
editor.putInt("age", 30);
editor.putLong("time", System.currentTimeMillis());
editor.putBoolean("default", true);
//提交数据,每次操作之后都要提交才会生效。
editor.commit();
//移除数据
editor.remove("default");
editor.commit();
//取值打印(key,默认值)
System.out.println(pref.getString("name", ""));
System.out.println(pref.getInt("age", 0));

二、SQLite数据库

        SQLite是D.Richeard Hipp用C语言编写的开源嵌入式数据库引擎。它支持大多数的SQL92标准,并且可以在所有主的操作系统上运行。支持高达2TB大小的数据库;以单个文件的形式存在;以B-Tree的数据结构形式存储在磁盘。

特点主要包括:
1、轻量级 一个动态库、单文件
2、独立性 没有依赖、无需安装
3、隔离性 全部在一个文件夹中
4、跨平台 支持众多操作系统
5、多语言接口 支持众多编程语言
6、安全性 事务处理

关于事务处理的安全性问题:
-通过数据库上的独立性和共享锁来实现独立事务处理。
-多个进程可以在同一时间从同一数据库读取数据,但只有一个可以写入数据。

关于SQLite的数据类型:
-SQLite支持NULL、INTEGER、REAL、TEXT和BLOB数据类型
-一次代表:空值、整型值、浮点值、字符串值、二进制对象

动态数据类型(弱引用)
-当某个值插入到数据库时,SQLite将会检查他的类型,如果该类型关联的列不匹配,SQLite则会尝试将该值转换成该列的类型,如果不能转换,则该值将作为本身的类型存储。

使用须知:
-由于资源占用少、性能良好和零管理成本,嵌入式数据库有了它的用武之地。
-没有可用于SQLite的网络服务器、只能通过网络共享可能存在文件锁定或者性能问题。
-只提供数据库级的锁定。
-没有用户账户概念,而是根据文件系统确定所有数据的权限。

SQLite使用:
SQLiteDatebase:
-提供了一些管理SQLite数据库的类
-提供创建,删除、执行SQL命令,并执行其他常见的数据库管理任务的方法
-每个程序的数据库名字是唯一的

常用语句:

//执行任何SQL语句
db.execSQL(String sql);
//插入(表名,空列的默认值,Map)
db.insert(String table, String nullColumnHack, ContentValues values);
//删除(表名,删除条件,删除条件数组值),在第二个参数比较完整时,第三个参数可以不要null;
db.delete(String table, String whereClause, String[] whereArgs);
//更新(表名,Map,更新条件,条件数组)
db.update(String table, ContentValues values, String whereClause, String[] whereArgs);
//查询(表名,查询列,条件语句,条件数组,分组,分组条件,排序,分页查询条件)
db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);
//使用SQL语句查询
db.rawQuery(sql, selectionArgs);

        Cursor是Android查询数据后得到的一个管理数据集合的类,正常情况下,如果查询得到的数据量较小时不会有内存问题,而且虚拟机能够保证Cursor最终会被释放掉。然而如果Cursor的数据量特别大,特别是如果里面有Blob信息时,应该保证Cursor占用的内存被及时的释放掉,而不是等待Gabage Collection来处理。并且Android明显是倾向于编程者手动的将Cursor close掉,因为在源代码中我们发现,如果等到垃圾回收器来回收时,也就是如果不手动关闭,系统会报错,会给用户以错误提示。

Cursor:游标接口,提供了遍历查询结果的方法,如移动指针方法move(),获得列值方法getString等。常用方法:

getCount()	//总记录条数
isFirst()	//判断是否是第一条记录
isLast()	//判断是否是最后一条记录
moveToFirst()	//移动到第一条记录
moveToLast()	//移动到最后一条记录
move(int offset)//移动到指定记录
moveToNext()	//移动到下一条记录
moveToPrevious()//移动到上一条记录
getColumnIndexOrThrow(String columnName)	//根据名称获得列索引
getInt(int columnIndex)				//获得指定列索引的int类型值
getString(int columnIndex)			//获得指定列索引的String类型值

具体使用方法参考:Android开发存储方式详解之SQLite使用实例

三、本地文件File存储

Activity的openFileOutput()方法可以用于把数据输出到文件中,创建的文件保存在/deta/data/<package name>/files目录。

//写死根目录/mnt/sdcard
File file = new File("/mnt/sdcard/test");
//获取根目录Environment.getExternalStorageDirectory()
File file = new File(Environment.getExternalStorageDirectory() + "/test");
		
//如果文件不存在,创建文件
if(!file.exists()){
	try {
		file.createNewFile();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
}else{
	Toast.makeText(this, "文件已经存在!", Toast.LENGTH_SHORT).show();
}

//删除文件
file.delete();

文件权限:

MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容。
MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
MODE_WORLD_READABLE:表示当前文件可以被其他应用读取。
MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。
从API第17开始的版本就不支持这种写法了。
MODE_PRIVATE 是数字0
MODE_WORLD_READABLE是数字1
MODE_WORLD_WRITEABLE是数字2

//这个目录是当前应用程序默认的数据存储目录
File file = this.getFilesDir();

//这个目录是当前应用程序默认的缓存文件的存放位置
//可以把一些不是非常重要的文件在此处创建使用
//如果手机内存不足的时候,系统会自动去删除APP的cache目录的数据
File file = this.getCacheDir();

//在/deta/data/<package name>/files目录指定权限创建文件夹(名字,权限)
File file = this.getDir("test", MODE_PRIVATE);

//外置存储目录
this.getExternalFilesDir(type);

//外置缓存目录,APP卸载数据也会清除(/mnt/sdcard/Android/data/<包名>)
File file = this.getExternalCacheDir();

文件读写详情可参考:Android开发存储方式详解之本地文件读写实例

四、ContentProvider访问其他程序信息(Android四大组件之一)

        其他程序通过Uri访问系统的ContentProvider数据。简单的说就是我们定义的ContentProvider是为其他应用提供数据的。系统联系人数据库存放位置如下:

/data/data/com.android.providers.conteacts/databases/contacts2.db

如何实现ContentProvider,首先必须要有一个数据库。然后执行下面方法

1、继承抽象类ContentProvider实现一系列针对数据的增、删、改、查等方法;
2、需要在AndroidMainfest.xml中完成对ContentProvider的注册。

<provider
      android:name="com.cx.datastored.MyContentProvider"
      android:authorities="com.cx.datastored" >
</provider>

注:注册的authorities属性值时全局唯一的,一般为包名

MyContentProvider参考代码如下:

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;

public class MyContentProvider extends ContentProvider {

	@Override
	public int delete(Uri arg0, String arg1, String[] arg2) {
		//根据Uri删除arg1指定的条件所匹配的全部记录
		return 0;
	}

	@Override
	public String getType(Uri arg0) {
		//返回当前Uri的MIME类型,如果该URI对应的数据可能包含多条记录,那么MIME类型字符串就是以vnd.android.dir开头
		//如果该URI对应的数据只有一条,该MIME类型字符串就是以vnd..android.cursor.item开头
		return null;
	}

	@Override
	public Uri insert(Uri arg0, ContentValues arg1) {
		//根据Uri插入arg1对应的数据
		return null;
	}

	@Override
	public boolean onCreate() {
		// 在ContentProvider创建后被调用
		return false;
	}

	@Override
	public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3,
			String arg4) {
		//根据Uri查询出arg2指定的条件所匹配的全部记录,并且可以指定查询那些列,以什么方式(arg4)排序
		return null;
	}

	@Override
	public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
		//根据Uri修改arg2指定的条件所匹配的全部记录
		return 0;
	}

}

ContentProvider的使用详情请参考:Android四大组件之ContentProvider

我们在访问系统联系人,系统的ContentProvider已经写好了,我们只需要根据Uri访问ContentProvider就可以了。

Uri是指通用资源标志符。就是我们要操作的数据。
-content://com.cx.data.storeed/mycontent/#
上面结构中的四部分分别为:
1、前缀表明数据受控于一个内容提供者。它从不修改,也就是schema
2、是指在AndroidMainfest.xml中我们注册的provider中的android:authorities属性值所对应的
3、具体操作于哪个条目

4、具体指定到哪个条目下的哪条记录(#表示通配符)

我们在解析Uri的时候,有要使用到Uri解析的工具类UriMatcher类,UriMatcher使用方法如下:

//实例化,UriMatcher.NO_MATCH表示不匹配任何路径的返回码
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
//往UriMatcher类里添加一个拼凑的Uri
//UriMatcher为一个Uri容器,容器里面包含着我们即将可能要操作的Uri
//如果通过match()方法匹配成功就返回code值
matcher.addURI("com.cx.datastored", "mycontent", 1);
//首先与找通过addURI()方法添加进来的Uri匹配
//匹配成功则返回设置的code(第三个参数)值,反之,返回一个UriMatcher.NO_MATCH常量(-1)
matcher.match(uri);

        当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver类来完成。使用Activity提供的getContentResolver()方法获取ContentResolver对象。
        ContentResolver类提供了与ContentProvider类相同签名的四个方法:参数完全一致

//该方法用于往ContentProvider添加数据
public Uri insert(Uri uri, ContentValues values)
//该方法用于从ContentProvider删除数据
public Uri delete(Uri uri, String selection, String[] selectionArgs)
//该方法用于更新ContentProvider中的数据
public Uri update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
//该方法用于从ContentProvider中获取数据
public Uri query(Uri uri, String[] projection, String selection, String selectionArgs, String sortOrder)

获取通讯录实例参考:使用ContentProvider添加获取通讯录信息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

c小旭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值