Android 数据库的操作
android平台中可以用来存储数据的方式很多,平时常用的有sharedpreference、file存储、sqlite数据库存储以用网络存储几种基本的存储方法。
下面比较详细的介绍如何实现数据的存储和获取:
轻量级的SharedPreferences存储,它是Android提供用来存储一些简单的配置信息的一种机制,例如,一些默认欢迎语、登录的用户名和密码等。其以键值对的方式存储,使得我们可以很方便的读取和存入。这个界面有点类似J2EE平台中的简单的
登陆界面。例如手机平台中游戏或者应用程序登陆之前要输入个人的用户名和密码的数据,我们就可以用SharedPreferences来存储数据。
在我们的上海电信项目中的登录界面就用到sharedPreferences来保存数据。SharedPreferences是通过Context 类的 getSharedPreferences方法操作的。preferences储存在文件中,而文件名用来指向preferences。
getSharedPreferences(String,int)。在一个类里面实例化,就可以在其它地方共享这些数据。目前这个类不支持多进程使用。
下面的代码是怎么从prefecences中读取数据:
public static final String PREF_FILE_NAME = “PrefFile”;
…
SharedPreferences preferences = getSharedPreferences(PREF_FILE_NAME, MODE_PRIVATE); int storedPreference = preferences.getInt(”storedInt”, 0); // use the values
其中MODE_PRIVATE 是 preferences 的操作模式,这是默认的模式,代表只有创建这个 preferences 的程序才能访问这个preferences。其他两个模式是MODE_WORLD_READABL和 MODE_WORLD_WRITEABLE: 1、MODE_WORLD_READABLE 表示其他程序对这个SharedPreferences只有只读权限。
2、MODE_WORLD_WRITEABLE则是其他程序同时拥有读写权限。
Activity Preferences:
shared preferences 可以被其他程序的组件使用。但是如果你不需要和其他组件共享 preferences,而是希望一个在activities内设一个私有的 preferences。可以用 activity 类的 getPreferences() 方法来实现。getPreference 方法用 activity 类的名字作为参数调用 getSharedPreference()。
上海电信项目中就提供了一个可以供其它程序的组件使用的SharedPreferences,以下是怎么获得SharedPreferences对象的代码:
SharedPreferences sp = this.getPreferences(Context.MODE_PRIVATE);
用 SharedPreference.Editor 往 preference 文件中保存数据。Editor 是 SharedPreference 的内部接口。
API中提供了
abstract SharedPreferences.Editor edit () 通过这个方法返回一个SharedPrefenences.Editor实例化对象
abstract SharedPreferences.Editor putBoolean (String key, boolean value)----设置boolean值存储
abstract SharedPreferences.Editor putFloat (String key, float value)----设置浮点型数据存储
abstract SharedPreferences.Editor putInt (String key, int value)----设置整形数据存储
abstract SharedPreferences.Editor putLong (String key, long value)----设置长整型 abstract SharedPreferences.Editor putString (String key, String value)---设置字符串数据存储
上海电信项目中我们是通过以下代码来保存用户登录的数据:(在LoginActivity类中)
Editor editor = sp.edit();
editor.putBoolean("ischecked", checked);// value to store
editor.putString("username", checked ? username : "");
editor.putString("password", checked ? password : "");
editor.commit();
当然我们也可以用SharedPreference.Editor 来remove和clear来删除数据。
那我们用SharedPreference保存的在android平台的哪个位置呢?SharedPreference是以xml格式自动保存的,在 DDMS中的File Explorer中展开到/data/data/<package name>/<project name>下可以找到一个XXX.xml的文件,在xml文档中保存了设置进去的值。整体效率来看不是特别的高,对于常规的轻量级而言比 SQLite要好不少,如果真的存储量不大可以考虑自己定义文件格式。xml处理时Dalvik会通过自带底层的本地XML Parser解析,比如XMLpull方式,这样对于内存资源占用比较好。
文件存储和传统的java文件操作一样,在android Api中提供了openFileInput和openFileOutput方法来读取设备上的文件。但是在默认状态下,文件是不能在不同的程序之间共享的,以上两个方法只支持读取该应用目录下的文件,读取非其自身目录下的文件将会抛出 FileNotFoundException异常。创建的文件存放在/data/data/<package name>/files目录下。关于文件流的操作是属于J2se的基本知识,这里就不再重复了,不了解的可以看看anroid的API。特别注意一点使用openFileOutput方法创建的文件只能被其调用的应用使用,其他应用无法读取这个文件,如果需要在不同的应用中共享数据,可以使用 Content Provider实现,关于Content Provider我们将在稍后的内容中介绍。如果我们要用到的一些额外的资源文件,我们可以把这些文件放在应用程序的/raw/raw下,那么就可以在你的应用中使用getResources获取资源后,以openRawResource方法(不带后缀的资源文件名)打开这个文件。
Resources myResources = getResources();
InputStream myFile = myResources.openRawResource(R.raw.myfilename);
除了前面介绍的读写文件外,Android还提供了诸如deleteFile、fileList 等方法来操作文件,不再赘述。
Sqlite数据库存储和ContentProvider对象介绍。
Android应用的另外一个方面:数据存储。用户可以将自己的数据存储到文件系统或者数据库当中,当然最经常的是,用户将自己的数据存储到SQLite 数据库当中。SQLite是Android所带的一个标准的数据库,它支持SQL语句,它是一个轻量级的嵌入式数据库。在我们上海电信和joyque电子书项目中sqlite数据库存储和ContentProvider对象是联合在一起使用的。
下面我们来了解ContentProvider和ContentResolver以及ContentProvider和ContentResolver中都用到的URI.
1、ContentProvider对象。因为Android这个系统和其他的操作系统还不太一样,读者需要记住的是,数据在Android当中是私有的,当然这些数据包括文件数据和数据库数据 以及一些其他类型的数据。那这个时候有读者就会提出问题,难道两个程序之间就没有办法对于数据进行交换?Android这么优秀的系统不会让这种情况发生 的。解决这个问题主要靠ContentProvider。一个Content Provider类实现了一组标准的方法接口,从而能够让其他的应用保存或读取此Content Provider的各种数据类型。也就是说,一个程序可以通过实现一个Content Provider的抽象接口将自己的数据暴露出去。外界根本看不到,也不用看到这个应用暴露的数据在应用当中是如何存储的,或者是用数据库存储还是用文件 存储,还是通过网上获得,这些一切都不重要,重要的是外界可以通过这一套标准及统一的接口和程序里的数据打交道,可以读取程序的数据,也可以删除程序的数 据,当然,中间也会涉及一些权限的问题。下边列举一些较常见的接口,这些接口如下所示。
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并且符合一定条件的数据。
我们可以参考上海电信项目中GamesProvider,joyque电子书项目的ReaderProvider都继承了ContentProvider 对象,并且都实现了以上的接口。
2.什么是ContentResolver。外界的程序通过ContentResolver接口可以访问ContentProvider提供的数据,在 Activity当中通过 getContentResolver()可以得到当前应用的ContentResolver实例。ContentResolver提供的接口和 ContentProvider中需要实现的接口对应,主要有以下几个。
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并且符合一定条件的数据。
在上海电信项目中的SocketService类,我们可以看到service层是怎么更新,插入,删除数据的。
ContentResolver conResolver;
conResolver.insert(Games.GameData.CONTENT_URI, cv);
conResolver.insert(Games.GameTypeData.CONTENT_URI, cv);
conResolver.insert(Games.GameTopicData.CONTENT_URI, cv);
/**
* 删除数据
*/
private void deleteData() {
conResolver.delete(Games.GameTopicData.CONTENT_URI, null, null);
conResolver.delete(Games.GameTypeData.CONTENT_URI, null, null);
conResolver.delete(Games.GameData.CONTENT_URI, Games.GameData.STATE+ "!=" + Games.GameData.STATE_INSTALLED, null);
}
/**
* 更新游戏表中的数据
* @param gi
* 游戏数据
*/
private void updateGamesItemData(GamesItem gi) {
ContentValues cv = gi.toContentValues();
conResolver.update(Uri.withAppendedPath(Games.GameData.CONTENT_URI,
String.valueOf(gi.get_id())), cv, null, null);
}
3.ContentProvider和ContentResolver中用到的Uri。
在ContentProvider和ContentResolver当中用到了Uri的形式通常有两种,一种是指定全部数据,另一种是指定某个ID的数据。我们看下面的例子。
content://contacts/people/ 这个Uri指定的就是全部的联系人数据。
content://contacts/people/1 这个Uri指定的是ID为1的联系人的数据。在上边两个类中用到的Uri一般由3部分组成
第一部分是:"content://" 。
第二部分是要获得数据的一个字符串片段。最后就是ID(如果没有指定ID,那么表示返回全部)。
由于URI通常比较长,而且有时候容易出错,且难以理解。所以,在Android当中定义了一些辅助类,并且定义了一些常量来代替这些长字符串的使用,例如下边的代码:Contacts.People.CONTENT_URI (联系人的URI)。像上面的Games.GameTopicData.CONTENT_URI、 Games.GameTypeData.CONTENT_URI、Games.GameData.CONTENT_URI 表示游戏分栏,游戏分类,游戏数据的URI。