首页 > 代码库 > 第五章 以数据为中心—数据存取(6)
第五章 以数据为中心—数据存取(6)
5.3 安全方便简单—使用SharedPreferences
前面操作文件和数据库都相对比较复杂,需要打开,读取,关闭等等操作。可能有人就想,如果我只是需要存取几个简单的数据,有没有简单点的方法呢?的确,在Android中也封装了一种轻便的数据存取的方法—Preferences。
Preferences是一种轻量级的数据存储机制,它将一些简单数据类型的数据,包括boolean类型、int类型、float类型、long类型以及String类型的数据,以键值对的形式存储在应用程序的私有Preferences目录(/data/data/<包名>/shared_prefs/)中。Preferences 只能在同一个包内使用,不能在不同的包之间使用。这种Preferences机制广泛应用于存储应用程序中的配置信息。
在Android平台上,只需要用一个Context的对象调用getSharedPreferences(String name,int mode)方法传入Preferences文件名和打开模式,就可以获得一个SharedPreferences的对象。若该Preferences文件不存在,在提交数据后会创建该Preferences文件。利用SharedPreferences对象可以调用一些getter方法,传入相应的键来读取数据。要对Preferences文件的数据进行修改,首先利用SharedPreferences对象调用edit()方法获得一个内部类Editor的对象,然后用这个Editor对象就可以对Preferences文件进行编辑了。注意,编译完毕后一定要调用commit()方法,这样才会把所做的修改提交到Preferences文件当中去。
下面是一个将EditText中的文本保存下来的例子:
// import略 public class PreferenceTest extends Activity {
private EditText edit; private static final String TEMP_NAME = "temp_name";
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); edit = new EditText(this); // 获得SharedPreferences对象 只读 SharedPreferences pre = getSharedPreferences(TEMP_NAME, MODE_WORLD_READABLE); // 读取“content” String content = pre.getString("content",""); edit.setText(content); setContentView(edit); } @Override protected void onStop() { super.onStop(); // 获得SharedPreferences.Editor对象 可写的 SharedPreferences.Editor editor = getSharedPreferences(TEMP_NAME, MODE_WORLD_WRITEABLE).edit(); // 保存“content” editor.putString("content", edit.getText().toString()); // 提交数据 editor.commit(); } } |
关于方法“public SharedPreferences getSharedPreferences(String name, int mode);”做些说明:
第一个参数是文件名称,第二个参数是操作模式。其中操作模式有三种:MODE_PRIVATE(私有);MODE_WORLD_READABLE(可读);MODE_WORLD_WRITEABLE(可写)。
可以看到,使用Preferences保存和读取数据非常的简单。
经验分享: 文件可以存储在SD卡上,而存储在SD卡上的文件,不会随着应用的卸载而被删除。但是Preferences保存的数据,如果应用被卸载了,其Preferences数据也就不存在了。这个是在使用Preferences保存数据时需要注意的。 |
5.4 我的数据大家用—ContentProvider、ContentResolver
在Android中,对数据的保护是很严密的,除了放在SD卡中的数据,一个应用所拥有的数据库、文件、等等内容,都是不允许其他应用直接访问的,但有时候,沟通是必要的,不仅对第三方很重要,对应用自己也很重要。解决这个问题可以靠ContentProvider。
一个ContentProvider实现了一组标准的方法接口,从而能够让其他的应用保存或读取此ContentProvider的各种数据类型。也就是说,一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据暴露出去,而被别的程序看到。其他程序也可以通过这ContentProvider读取、修改、删除数据,当然,中间也会涉及到一些权限的问题。下边列举一些较常见的接口,这些接口如表5-3所示。
接口 | 说明 |
query(Uri uri, String[] projection, String selection, String[] selectionArgs,String sortOrder) | 通过Uri进行查询,返回一个Cursor。 |
insert(Uri url, ContentValues values) | 将一组数据插入到Uri指定的地方。 |
update(Uri uri, ContentValues values, String where, String[] selectionArgs) | 更新Uri指定位置的数据。 |
delete(Uri url, String where, String[] selectionArgs) | 删除指定Uri并且符合一定条件的数据。 |
表5-3 ContentProvider的接口
经验分享: Android 系统为一些常见的数据类型(如音乐、视频、图像、手机通信录联系人信息等)内置了一系列的ContentProvider,这些都位于android.provider包下。持有特定的许可,可以在自己开发的应用程序中访问这些Content Provider。 |
外界的程序通过ContentResolver接口可以访问ContentProvider提供的数据,在Activity 当中通过getContentResolver()可以得到当前应用的ContentResolver实例。ContentResolver提供的接口和ContentProvider 中需要实现的接口对应,详细请参考表5-3。
在内容的提供者(ContentProvider)和使用者(ContentResolver)中我们都看到一个常用的对象Uri,这个对象类似一个地址,通常有两种,一种是指定全部数据,另一种是指定某个ID 的数据。我们看下面的例子。
content://contacts/people/ 这个Uri指定的就是全部的联系人数据。 content://contacts/people/1 这个Uri指定的是ID为1的联系人的数据。 |
Uri一般由3 部分组成:
l 第一部分是:"content://" 。
l 第二部分是要获得数据的一个字符串片段。
l 最后就是ID(如果没有指定ID,那么表示返回全部)。
由于 URI 经常比较长,而且有时候容易出错,且难以理解。所以,在Android 当中定义了一些辅助类,并且定义了一些常量来代替这些长字符串的使用,例如下边的代码:
Uri mUri = android.provider.Contacts.People.CONTENT_URI; //联系人的URI实际等于: Uri mUri = Uri.parse("content://contacts/people"); |
上述都是理论的分析,下面我们通过一个例子来看看具体是如何使用的,我们要获取出手机的联系人列表,将其显示出来。
// import略 public class ContentResolverTest extends Activity {
// 查询Content Provider时希望返回的列 private String[] columns = { ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts._ID,}; private Uri contactUri = ContactsContract.Contacts.CONTENT_URI; private TextView tv;
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); tv = new TextView(this); String result = getQueryData(); tv.setTextColor(Color.GREEN); tv.setTextSize(20.0f); tv.setText("ID 名字 " + result); setContentView(tv); } /** * 获取联系人列表的信息,返回 String对象 */ public String getQueryData() { String result = ""; // 获取ContentResolver对象 ContentResolver resolver = getContentResolver(); Cursor cursor = resolver.query(contactUri, columns, null, null, null); // 获得_ID字段的索引 int idIndex = cursor.getColumnIndex(ContactsContract.Contacts._ID); // 获得Name字段的索引 int nameIndex = cursor .getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME); // 遍历Cursor提取数据 for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { result = result + cursor.getString(idIndex) + ","; result = result + cursor.getString(nameIndex) + ";"; } cursor.close(); return result; } } |
经验分享: 联系人可能保存在手机中,也可能保存在手机卡中。上述代码只是从手机中获取了联系人的列表。在实际开发中,如果有这种需求,我们还需要从手机卡中获取所有联系人,并且与手机中的联系人做对比,最终得到一份完整的联系人列表。具体如何从手机卡中获取联系人,这里不做说明,读者可以从互联网查找相关资料。 |
经验分享: 在Android开发中,如果需要访问硬件设备,就经常会遇到权限问题。如果在调试过程中出现类似“Android Permission denied”错误,就要看看是否用到了系统功能而没有增加相应的权限。 比如,上面的例子,我们就需要添加相应的权限。 <uses-permission android:name="android.permission.READ_CONTACTS" /> <!-- 读取联系人权限 --> <uses-permission android:name="android.permission.WRITE_CONTACTS" /> <!-- 写联系人权限 --> |
第五章 以数据为中心—数据存取(6)