Android 数据存储
关于Android开发时涉及到的数据存储有好几种,在这里,我总结了四种在开发中常用的存储方法,有SQLite数据库存储,contentprovider,contentprovider,File存储。对于简单的sharedpreferences存储和File存储就简述,而SQLite数据库存储和contentprovider者详细记录。
学习前,需要明白几个名词,
Cursor(游标):数据缓冲区,放查询记录,执行查询时,都会返回一个 Cursor来遍历表中的数据,提醒一点,在第一次读取Cursor对象中的数据时,一定要先移动游标,否则此游标的位置在第一条记录之前,会引发异常(moveToFirst())。
contentvalues:类似于集合hashmap,是一种存储机制,存放的类型为基本数据,以键值对的形式存储。
Uri:资源标识符,是字符串,可用来定位区域可用的资源,有点像JPS,URI一般由三部分组成:1 访问资源的命名机制。2 存放资源的主机名。3 资源自身的名称,由路径表示。它两好基友ContentUris和UriMatcher,ContentUris类用于操作Uri路径后面的ID部分,UriMatcher类用于匹配Uri。
第一种:SQLite数据库存储
关键字:轻量级,开源,面向源有限的设备(手机),新API,SQLiteOpenHelper 类,
data/< 项目文件夹 >/databases/ , execSQL()
作为Android数据存储中最流行的嵌入式数据库,它支持 SQL 查询,占用内存小,可以自由复制,所有东西都放在同一个文件,由于 JDBC 不适合手机这种内存受限设备,所以 Android 开发人员需要学习新的 API 来使用 SQLite,execSQL() 方法可以执行SQL语句,但要注意语句格式,还有很多关于SQLite是信息就不多说了,下面就进行数据库的创建与增删改查。
创建数据库是需要借助继承SQLiteOpenHelper 类,实现几个方法然后实例化该类,当在程序中调用这个类的方法getWritableDatabase()和getReadableDatabase()进行写读操作的时候,如果当时没有数据库,那么Android系统会自动创建一个数据库。代码示例:
package com.example.shuju;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
public class DatabaseHelper extends SQLiteOpenHelper{
private static int version = 1;
/*这个方法需要四个参数:上下文环境(例如,一个 Activity),数据库名字,一个可选的游标工厂(通常是 Null),
* 一个代表你正在使用的数据库模型版本的整数*/
public DatabaseHelper(Context context, String name,
CursorFactory factory, int version) {
super(context, name, factory, version);
}
public DatabaseHelper(Context context, String name) {
this(context, name, version);
}
public DatabaseHelper(Context context, String name, int version) {
this(context, name, null, version);
}
//在数据库第一次生成的时候会调用这个方法,一般我们在这个方法里生成数据表
@Override
public void onCreate(SQLiteDatabase db) {
// 创建数据库的SQL
}
//当数据库需要升级时,Android系统会自动调用这个方法,一般我们在这里写删除表并创建新表的操作
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
建表与增加数据,表创建好之后,通过insert(String table, String nullColumnHack, ContentValues values)方法插入数据,
db.execSQL("create table tab(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)");
ContentValues values = new ContentValues();
for(int i=0;i<10;i++){
values.put("name", "test" + i);
db.insert("tab", "_id", values);
}
修改数据,方法update(String table, ContentValues values, String whereClause,
String[] whereArgs)参数的具体含义代码里有,代码示例:
ContentValues args = new ContentValues();
args.put("body", "修改后啦!");
String[] title = new String[] { "第二条数据" };
DatabaseHelper helper = new DatabaseHelper(SQLiteActivity.this,
"dbk");
// 定义写数据库操作
SQLiteDatabase db = helper.getWritableDatabase();
/*
* 修改数据库 第一个参数是:数据库表名 第二个参数是:要修改的字段和要更新的内容
* 第三个参数是:条件,相当于SQL中的where部分
* 第四个参数是:如果在第三个参数中有“?”符号,那么第四个参数的字串符会代替第三个的“?”部分
*/
db.update("dbk", args, "title=?", title);
db.close();
删除数据,delete(String table, String whereClause, String[] whereArgs),代码示例:
try {
DatabaseHelper helper = new DatabaseHelper(
SQLiteActivity.this, "dbk");
// 定义写数据库操作
SQLiteDatabase db = helper.getWritableDatabase();
/*
* 删除操作 第一个参数是:数据库表名 第二个参数是:条件,相当于SQL中的where部分
* 第三个参数是:如果在第三个参数中有“?”符号,那么第四个参数的字串符会代替第三个的“?”部分
*/
db.delete("dbk", "title='第二条数据'", null);
setTitle("删除title为第二条数据的记录");
db.close();
} catch (Exception e) {
}
查询数据,android提供的query()和rawQuery()方法执行查询,代码示例:
DatabaseHelper helper = new DatabaseHelper(SQLiteActivity.this,
"dbk");
// 定义读数据库操作
SQLiteDatabase db = helper.getReadableDatabase();
String col[] = { "title", "body" };
/*
* 执行数据库查询功能 第一个参数:表名 第二个参数:要查询的列的信息
* 第三个参数:条件,相当于SQL中的where部分,如果想查询所以则为null
* 第四个参数:如果在第三个参数中有“?”符号,那么第四个参数的字串符会代替第三个的“?”部分
* 第五个参数:定义查询出来的数据是否分组,相当于SQL的GROUP BY,null为不分组
* 第六个参数:相当于SQL的having部分 第七个参数:相当于SQL的ORDEY BY来描述是否排序,为null则不排序
*/
Cursor cusor = db.query("dbk", col, null, null, null, null,
null);
if (cusor.moveToNext()) {
String title = cusor.getString(cusor
.getColumnIndex("title"));
String body = cusor.getString(cusor.getColumnIndex("body"));
final Integer num = cusor.getCount();
setTitle(title);
// 弹出一个对话框,来显示第一条数据
dialog(SQLiteActivity.this, title, body, num).show();
} else {
// 如果数据库中没有数据则提示
new AlertDialog.Builder(SQLiteActivity.this)
.setTitle("数据库中没有数据")
.setPositiveButton("确定",
new DialogInterface.OnClickListener() {
@Override
public void onClick(
DialogInterface dialog,
int which) {
}
}).create().show();
}
db.close();
第二种:contentprovider
关键字:对外共享数据,统一了数据的访问方式,四大组件之一,
在处处可见“云”的今天,程序间的数据交互需求令ContentProvider存储机制变成必不可少的一部分。而它也是最复杂的一种存储方式,作为四大组件之一,重要性可想而知,他的用处我拿一个比喻来形容,就是应用程序之间的桥梁,有了一定的权限,可以在程序间共享数据。
下面通过是代码示例,演示一下如何在应用之间相互获取数据。
首先在AndroidManifest.xml声明ContentProvider:其中authorities属性定义了此ContentProvider的Uri标识
<provider android:name=".MyProvider" android:authorities="com.test.MyProvider"/>
在应用程序A中,继承ContProvider类,并重写其中方法。
public class MyProvider extends ContentProvider{
2 @Override
3 public int delete(Uri uri, String selection, String[] selectionArgs) {
4 // TODO Auto-generated method stub
5 return 0;
6 }
7
8 @Override
9 public String getType(Uri uri) {
10 // TODO Auto-generated method stub
11 return null;
12 }
13
14 @Override
15 public Uri insert(Uri uri, ContentValues values) {
16 return null;
17 }
18
19 //在Create中初始化一个数据库
20 @Override
21 public boolean onCreate() {
22 SQLiteDatabase db = this.getContext().openOrCreateDatabase("test_db.db3", Context.MODE_PRIVATE, null);
23 db.execSQL("create table tab(_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)");
24 ContentValues values = new ContentValues();
25 values.put("name", "test");
26 db.insert("tab", "_id", values);
27 db.close();
28 return true;
29 }
30
31 //实现query方法
32 @Override
33 public Cursor query(Uri uri, String[] projection, String selection,
34 String[] selectionArgs, String sortOrder) {
35 SQLiteDatabase db = this.getContext().openOrCreateDatabase("test_db.db3", Context.MODE_PRIVATE, null);
36 Cursor c = db.query("tab", null, null, null, null, null,null);
37 return c;
38 }
39
40 @Override
41 public int update(Uri uri, ContentValues values, String selection,
42 String[] selectionArgs) {
43 // TODO Auto-generated method stub
44 return 0;
45 }
46 }
当外部应用需要对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中获取数据。
这些方法的第一个参数为Uri,代表要操作的ContentProvider和对其中的什么数据进行操作,
在应用程序B中,通过ContentResolver获取程序A的ContentProvider中的数据。
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//获取上下文
Context ctx = MainActivity.this;
//获取ContentResolver对象
ContentResolver resolver = ctx.getContentResolver();
//获取Uri对象
Uri uri = Uri.parse("content://com.test.MyProvider");
//获取数据
Cursor c = resolver.query(uri, null, null, null, null);
c.moveToFirst();
for(int i=0; i<c.getCount(); i++){
int index = c.getColumnIndexOrThrow("name");
String src = c.getString(index);
Log.d("", src);
c.moveToNext();
}
}
}
第三种:Sharedpreferences
关键字:轻量级,一些配置信息,简洁,键值对,最容易理解和使用,存储基本数据类型,无查询
data/data/包名 /shared_prefs/,xml存储
sharedpreferences可以将数据保存着应用软件的私有存储区,这些存储区的数据只能被写入这些数据的软件读取,
这类存储比较简单,就简述实现过程,
获取SharedPreferences对象的方法
SharedPreferences sharedPreferences = getSharedPreferences("ljq", Context.MODE_PRIVATE);
第一个参数用于指定该文件的名称,名称不用带后缀,后缀会由Android自动加上。方法的第二个参数指定文件的操作模式
使用SharedPreferences存取数据
Editor editor = sharedPreferences.edit();//获取编辑器
editor.putString("name", "林计钦");
editor.putInt("age", 24);
editor.commit();//提交修改
生成的ljq.xml文件内容如下:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="name">林计钦</string>
<int name="age" value="24" />
</map>
第四种:File存储
关键词:大量数据,文本图片音频,权限,openFileInput,openFileOutput,
/data/data/<包>/files/***,SDCard
file存储可以存储大量数据,比如说图片音频。所以就会与内存卡关联,存储在本机上就注意openFileInput,openFileOutput
两方法,openFileOutput()方法的第一参数用于指定文件名称,第二参数用于指定操作模式,有四种模式,分别为:
Context.MODE_PRIVATE = 0(默认,,只能被应用本身访问)
Context.MODE_APPEND = 32768(检查文件是否存在,存在就往文件追加内容,否则就创建新文件。)
Context.MODE_WORLD_READABLE = 1(当前文件可以被其他应用读取;)
Context.MODE_WORLD_WRITEABLE = 2(当前文件可以被其他应用写入。)
最常用的还是存储在外置内存卡上,要往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();
}
<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>