(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(参数)进行存储和访问
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>
下面一一介绍这些方法和参数
SharedPreferences sharedPreferences = getSharedPreferences("test", Context.MODE_PRIVATE);
//getString()第二个参数为缺省值,如果preference中不存在该key,将返回缺省值
String name = sharedPreferences.getString("name", "");
int age = sharedPreferences.getInt("age", 1);
Context otherAppsContext = createPackageContext("com.gzsll.io", Context.CONTEXT_IGNORE_SECURITY);
com.gzsll.io就是其他程序的包名
3.使用SQLite数据库进行数据存储和访问
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对数据库进行管理
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});
使用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)共享
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/开头.
<provider android:name=".DictProvider" android:authorities="com.gzsll.provider.dictprovider"/>
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()方法。