本文主要讲解Android开发的数据保存技术。Android的数据保存技术主要有preference,本地文件,SQLite轻量级数据库,和Content Provider。本文只要讲SQLite和Conent Provider。preference和本地文件,将放在后面讨论。

SQLite

Android通过SQLite库提供了完善的关系数据库功能,而没有强加任何额外的限制。通过使用SQLite,可以为每一个应用程序创建独立的关系数据库。

所有的Android数据库都存储在/data/data/<package_name>/databases文件夹下。默认条件下,所有的数据库都是私有的,并且只能被创建它们的应用程序访问。要跨应用程序共享数据库,可以使用内容提供器。

SQLite是一个关系数据管理系统。它被普遍认为是:开源,兼容标准,轻量级,Single-tier。

可以用一个例子来演示SQLite。该例子将记录存储在一个数据库中,然后显示出来。

新建一个HelloSQLite的程序。

需要在某个地方放置该数据库中描述的一些常量,所以要创建一个Constants接口。

代码如下:

/*

* Android开发之数据保存技术(一)

* Constants.java

* Created on: 2011-8-15

* Author: blueeagle

* Email: liujiaxiang@gmail.com

*/

[java] view plain copy
  1. packagecom.blueeagle;
  2. importandroid.provider.BaseColumns;
  3. publicinterfaceConstantsextendsBaseColumns{
  4. /**Calledwhentheactivityisfirstcreated.*/
  5. publicstaticfinalStringTABLE_NAME="HelloSQLite";
  6. publicstaticfinalStringTIME="time";
  7. publicstaticfinalStringTITLE="title";
  8. }


每个事件都将作为HeloSQLite表中的一行进行存储。每行都包含一个_id、time和title列。_id是主键,在扩展的BaseColums接口中声明。time和title分别作为时间和事件标记。

使用SQliteOpenHelper。接下来,创建一个名为SQLiteData的帮助器来表示数据库本身。这个类扩展自Android的SQLiteOpenHelper类,它负责管理数据库的创建和版本。需要做的就是提供一个构造方法并且覆写两个方法。

代码如下:

[java] view plain copy
  1. /*
  2. *Android开发之数据保存技术(一)
  3. *MySQLite.java
  4. *Createdon:2011-8-16
  5. *Author:blueeagle
  6. *Email:liujiaxiang@gmail.com
  7. */
  8. packagecom.blueeagle;
  9. importandroid.content.Context;
  10. importandroid.database.sqlite.SQLiteDatabase;
  11. importandroid.database.sqlite.SQLiteDatabase.CursorFactory;
  12. importandroid.database.sqlite.SQLiteOpenHelper;
  13. importstaticcom.blueeagle.Constants.TABLE_NAME;
  14. importstaticcom.blueeagle.Constants.TIME;
  15. importstaticcom.blueeagle.Constants.TITLE;
  16. importstaticandroid.provider.BaseColumns._ID;
  17. publicclassMySQLiteextendsSQLiteOpenHelper{
  18. privatestaticfinalStringDATABASE_NAME="MySQLite.db";
  19. privatestaticfinalintDATABASE_VERSION=1;
  20. publicMySQLite(Contextcontext,Stringname,CursorFactoryfactory,
  21. intversion){
  22. super(context,DATABASE_NAME,factory,DATABASE_VERSION);
  23. //TODOAuto-generatedconstructorstub
  24. }
  25. @Override
  26. publicvoidonCreate(SQLiteDatabasedb){
  27. //TODOAuto-generatedmethodstub
  28. db.execSQL("CREATETABLE"+TABLE_NAME+"("+_ID+"INTEGERPRIMARYKEYAUTOINCREMENT,"+TIME+"INTEGER,"+TITLE+"TEXTNOTNULL);");
  29. }
  30. @Override
  31. publicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){
  32. //TODOAuto-generatedmethodstub
  33. db.execSQL("DROPTABLEIFEXISTS"+TABLE_NAME);
  34. onCreate(db);
  35. }
  36. }


首次访问数据库时,SQLiteOpenHelper将注意到该数据库不存在,并调用onCreate()方法来创建它。

定义Activity主程序。

在HelloSQLite程序中做的第一次尝试是使用本地的SQLite数据库来存储事件,并将这些事件显示为TextView中的一个字符串。

布局xml文件如下:

[html] view plain copy
  1. main.xml
  2. <?xmlversion="1.0"encoding="utf-8"?>
  3. <ScrollViewxmlns:android="http://schemas.android.com/apk/res/android"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. >
  7. <TextView
  8. android:id="@+id/myText"
  9. android:layout_width="fill_parent"
  10. android:layout_height="wrap_content"
  11. />
  12. </ScrollView>


这段代码使用一个ScrollView,以防太多的时间沾满了屏幕。

对于HelloSQLite.java的实现如下所示:相关代码有注释说明。

[java] view plain copy
  1. packagecom.blueeagle;
  2. /*
  3. *Android开发之数据保存技术(一)
  4. *HelloSQLite.java
  5. *Createdon:2011-8-16
  6. *Author:blueeagle
  7. *Email:liujiaxiang@gmail.com
  8. */
  9. importandroid.app.Activity;
  10. importandroid.content.ContentValues;
  11. importandroid.database.Cursor;
  12. importandroid.database.sqlite.SQLiteDatabase;
  13. importandroid.os.Bundle;
  14. importandroid.widget.TextView;
  15. importstaticcom.blueeagle.Constants.TABLE_NAME;
  16. importstaticcom.blueeagle.Constants.TIME;
  17. importstaticcom.blueeagle.Constants.TITLE;
  18. importstaticandroid.provider.BaseColumns._ID;
  19. publicclassHelloSQLiteextendsActivity{
  20. /**Calledwhentheactivityisfirstcreated.*/
  21. privateMySQLitemySqlite;
  22. privatestaticString[]FROM={_ID,TIME,TITLE};
  23. privatestaticStringORDER_BY=TIME+"DESC";
  24. @Override
  25. publicvoidonCreate(BundlesavedInstanceState){
  26. super.onCreate(savedInstanceState);
  27. setContentView(R.layout.main);
  28. mySqlite=newMySQLite(this);
  29. try{
  30. addItem("Hello,Android!");
  31. Cursorcursor=getItems();
  32. showItems(cursor);
  33. }
  34. finally{
  35. mySqlite.close();
  36. }
  37. }
  38. //显示查询结果
  39. privatevoidshowItems(Cursorcursor){
  40. //TODOAuto-generatedmethodstub
  41. StringBuilderbuilder=newStringBuilder("Saveditems:\n");
  42. while(cursor.moveToNext()){
  43. longid=cursor.getLong(0);
  44. longtime=cursor.getLong(1);
  45. Stringtitle=cursor.getColumnName(2);
  46. builder.append(id).append(":");
  47. builder.append(time).append(":");
  48. builder.append(title).append("\n");
  49. }
  50. TextViewmyTextView=(TextView)findViewById(R.id.myText);
  51. myTextView.setText(builder);
  52. }
  53. //此函数接受一个Cursor作为输入并格式化,以便用户能够理解输出的内容
  54. //查询条目方法
  55. privateCursorgetItems(){
  56. //TODOAuto-generatedmethodstub
  57. SQLiteDatabasedb=mySqlite.getReadableDatabase();
  58. Cursorcursor=db.query(TABLE_NAME,FROM,null,null,null,null,ORDER_BY);
  59. startManagingCursor(cursor);
  60. returncursor;
  61. }
  62. //因为查询不用修改数据库,因此利用只读句柄,然后调用查询的query方法来执行SQL语句,FROM是
  63. //想要使用的列构成的数组,ORDER_BY告诉SQLite按照从新到旧的顺序返回查询结果。
  64. //添加条目方法
  65. privatevoidaddItem(Stringstring){
  66. //TODOAuto-generatedmethodstub
  67. SQLiteDatabasedb=mySqlite.getWritableDatabase();
  68. ContentValuesvalues=newContentValues();
  69. values.put(TIME,System.currentTimeMillis());
  70. values.put(TITLE,string);
  71. db.insert(TABLE_NAME,null,values);
  72. }
  73. //因为要修改数据库,所以调用getWritableDatabase()方法来获取数据库的一个写句柄,当然也可以获取
  74. //到读句柄。
  75. }


完成上述文件-》运行,即可看到结果显示出来。这样就完成了第一个Android数据库程序。

当然,这里面需要注意的问题:

1. 新建数据库的问题

新建数据库的时候,会遇到我们用:

db.execSQL("CREATE TABLE "+ TABLE_NAME+"("+_ID+"INTEGER PRIMARY KEY AUTOINCREMENT,"+TIME+"INTEGER,"+TITLE+"TEXT NOT NULL);");

这样一条语句。有时候SQL语句书写错误,比如少一个空格就会引起程序异常退出。这个时候建议在db.execSQL()函数中填写一个字符串变量,然后把自己写的SQL语句赋给字符串变量,在做赋值操作的时候,先打印出来看看,是不是少空格,多+号什么的小错误。

2. 版本号的问题

关于构造函数中的版本号,是有明确的说明的。

public MySQLite(Context context, String name, CursorFactory factory,

int version) {

super(context, DATABASE_NAME, factory,DATABASE_VERSION);

这个版本号version当你有新版本的时候,则做更新操作,新版本的版本号将要比老版本高,如果此时修改版本号,不是向高修改,而是向低修改的话,程序就会发生异常了。

3. 数据库文件的问题

对于onCreate()方法,在程序运行的时候,只运行一次,运行的这一次就是去创建数据库。将数据库的文件存储在SD卡中。路径是data/data/包名/databases里。可以在Eclipse里通过DDMS里的File Explorer来查看。当数据库文件存在了以后,则不会再次运行。

完成了上述例子,就算完成了一个数据库的应用。但是如果列表中有数千个或者上百万个事件。程序将运行的非常慢。甚至于耗尽内存。解决办法就是数据绑定。

有了数据绑定,只需要几行代码,就可以将数据连接到视图,从而实现需求。为了演示,我们修改上面的实例。

将主程序HelloSQLite.java继承ListActivity而不是Activity。

将代码修改为如下所示:

[java] view plain copy
  1. packagecom.blueeagle;
  2. /*
  3. *Android开发之数据保存技术
  4. *HelloSQLite.java
  5. *Createdon:2011-8-16
  6. *Author:blueeagle
  7. *Email:liujiaxiang@gmail.com
  8. */
  9. importandroid.app.ListActivity;
  10. importandroid.content.ContentValues;
  11. importandroid.database.Cursor;
  12. importandroid.database.sqlite.SQLiteDatabase;
  13. importandroid.os.Bundle;
  14. importandroid.widget.SimpleCursorAdapter;
  15. importstaticcom.blueeagle.Constants.TABLE_NAME;
  16. importstaticcom.blueeagle.Constants.TIME;
  17. importstaticcom.blueeagle.Constants.TITLE;
  18. importstaticandroid.provider.BaseColumns._ID;
  19. publicclassHelloSQLiteextendsListActivity{
  20. /**Calledwhentheactivityisfirstcreated.*/
  21. privateMySQLitemySqlite;
  22. privatestaticString[]FROM={_ID,TIME,TITLE};
  23. privatestaticStringORDER_BY=TIME+"DESC";
  24. //@Override
  25. publicvoidonCreate(BundlesavedInstanceState){
  26. super.onCreate(savedInstanceState);
  27. setContentView(R.layout.main);
  28. mySqlite=newMySQLite(this);
  29. try{
  30. addItem("Hello,Android!");
  31. Cursorcursor=getItems();
  32. showItems(cursor);
  33. }
  34. finally{
  35. mySqlite.close();
  36. }
  37. }
  38. privatestaticint[]TO={R.id.rowid,R.id.time,R.id.title};
  39. privatevoidshowItems(Cursorcursor){
  40. SimpleCursorAdapteradapter=newSimpleCursorAdapter(this,R.layout.item,cursor,FROM,TO);
  41. //这里有必要说明一下SimpleCursorAdapter构造函数的5个参数。1.对应于当前Activity的引用,2.一个资源,它定义一个列表条目的视图,
  42. //3.数据集光标,4.一组列名称,数据来源于这些列。5.视图列表,这是数据的目的地。
  43. setListAdapter(adapter);
  44. }
  45. privateCursorgetItems(){
  46. SQLiteDatabasedb=mySqlite.getReadableDatabase();
  47. Cursorcursor=db.query(TABLE_NAME,FROM,null,null,null,null,ORDER_BY);
  48. startManagingCursor(cursor);
  49. returncursor;
  50. }
  51. privatevoidaddItem(Stringstring){
  52. //TODOAuto-generatedmethodstub
  53. SQLiteDatabasedb=mySqlite.getWritableDatabase();
  54. ContentValuesvalues=newContentValues();
  55. values.put(TIME,System.currentTimeMillis());
  56. values.put(TITLE,string);
  57. db.insert(TABLE_NAME,null,values);
  58. }
  59. }


将main.xml修改成如下形式:

[html] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. >
  6. <ListView
  7. android:id="@android:id/list"
  8. android:layout_height="wrap_content"
  9. android:layout_width="wrap_content">
  10. </ListView>
  11. <TextView
  12. android:id="@android:id/empty"
  13. android:layout_height="wrap_content"
  14. android:layout_width="wrap_content"
  15. android:text="empty!">
  16. </TextView>
  17. </LinearLayout>


增加item.xml为如下:

[html] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="horizontal"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. android:padding="10sp"
  7. >
  8. <TextView
  9. android:id="@+id/rowid"
  10. android:layout_height="wrap_content"
  11. android:layout_width="wrap_content">
  12. </TextView>
  13. <TextView
  14. android:id="@+id/rowidcolon"
  15. android:layout_height="wrap_content"
  16. android:layout_width="wrap_content"
  17. android:text=":"
  18. android:layout_toRightOf="@id/rowid">
  19. </TextView>
  20. <TextView
  21. android:id="@+id/time"
  22. android:layout_height="wrap_content"
  23. android:layout_width="wrap_content"
  24. android:layout_toRightOf="@id/rowidcolon">
  25. </TextView>
  26. <TextView
  27. android:id="@+id/timecolon"
  28. android:layout_height="wrap_content"
  29. android:layout_width="wrap_content"
  30. android:text=":"
  31. android:layout_toRightOf="@id/time">
  32. </TextView>
  33. <TextView
  34. android:id="@+id/title"
  35. android:layout_height="fill_parent"
  36. android:layout_width="wrap_content"
  37. android:textStyle="italic"
  38. android:ellipsize="end"
  39. android:singleLine="true"
  40. android:layout_toRightOf="@id/timecolon">
  41. </TextView>
  42. </RelativeLayout>


运行结果如图所示。

android 这篇文章让我更加明白android数据库存储_第1张图片

当然,这只是一个DEMO,用来展示如何使用SQLite,这个DEMO存在一些问题。其他应用程序都不能向事件数据库添加内容,甚至于无法看这些事件。那么针对这一点,引出了Android里的内容提供器,即ContentProvider。

内容提供器

在Android安全模型中,一个应用程序编写的文件无法被其他任何应用程序所读写。每个应用程序都有自己的Linux用户ID和数据目录,以及其受保护的内存空间。Android程序可以通过下面两种方式进行彼此间的通信。

第一种是IPC(Inter-Process Communication,进程间通信):一个进程使用AIDL(Android Interface Definition Language,接口定义语言)和IBinder接口声明一个任意的API。调用该API时,将在进程间安全且有效地队参数进行编组。这项先进技术用于对后台Service线程进行远程过程调用。

第二种就是ContentProvider:进程在系统中将他们本身注册为某些数据类型的提供者。请求该信息时,Android就会通过一个固定的API调用这些进程,以它们认为合适的方式查询或者修改内容。

ContentProvider管理的任何信息部分都通过一个URI来寻址,这个URI类似于以下形式:content://authority/path/id

其中content://是标准要求的前缀。authority是提供者的名称,建议使用完全限定包名称,避免出现名称冲突。Path是提供者内部的一个虚拟目录,用于标识被请求的数据类型。Id是被请求的特定记录的主键,要请求获得具有特定类型的所有记录,可以省略此参数以及后面的斜杠。

Android已经内置提供了几个提供者,包括:

content://browser;

content://contacts;

content://media;

content://settings。

下面我们就来演示如何使用内容提供器。

将HelloSQLite程序改为使用内容提供器的。对于HelloSQLite的提供者,下面都是有效的URI:

content://com.blueeagle.HelloSQLite/3 ——表示取id为3的数据

content://com.blueeagle.HelloSQLite/ ——表示取所有数据

首先需要向Contants.java添加两个常量:

public static final String AUTHORITY = "com.blueeagle.HelloSQLite";

public static final Uri CONTENT_URI = Uri.parse("content://"+AUTHORITY+"/"+TABLE_NAME);

接下来可以对HelloSQLite类做一些修改:

代码如下:

[java] view plain copy
  1. packagecom.blueeagle;
  2. /*
  3. *Android开发之数据保存技术(一)
  4. *HelloSQLite.java
  5. *Createdon:2011-8-16
  6. *Author:blueeagle
  7. *Email:liujiaxiang@gmail.com
  8. */
  9. importandroid.app.ListActivity;
  10. importandroid.content.ContentValues;
  11. importandroid.database.Cursor;
  12. importandroid.os.Bundle;
  13. importandroid.widget.SimpleCursorAdapter;
  14. importstaticcom.blueeagle.Constants.TIME;
  15. importstaticcom.blueeagle.Constants.TITLE;
  16. importstaticcom.blueeagle.Constants.CONTENT_URI;
  17. importstaticandroid.provider.BaseColumns._ID;
  18. publicclassHelloSQLiteextendsListActivity{
  19. /**Calledwhentheactivityisfirstcreated.*/
  20. //privateMySQLitemySqlite;
  21. privatestaticString[]FROM={_ID,TIME,TITLE};
  22. privatestaticStringORDER_BY=TIME+"DESC";
  23. //@Override
  24. publicvoidonCreate(BundlesavedInstanceState){
  25. super.onCreate(savedInstanceState);
  26. setContentView(R.layout.main);
  27. addItem("Hello,Android!");
  28. Cursorcursor=getItems();
  29. showItems(cursor);
  30. }
  31. privatestaticint[]TO={R.id.rowid,R.id.time,R.id.title};
  32. //显示查询结果
  33. privatevoidshowItems(Cursorcursor){
  34. //TODOAuto-generatedmethodstub
  35. SimpleCursorAdapteradapter=newSimpleCursorAdapter(this,R.layout.item,cursor,FROM,TO);
  36. setListAdapter(adapter);
  37. }
  38. //使用ContentProvider时,geiItems方法也化简了
  39. privateCursorgetItems(){
  40. returnmanagedQuery(CONTENT_URI,FROM,null,null,ORDER_BY);
  41. }
  42. //此处使用Activity.managedQuery()方法,将内容URI,感兴趣的列表和应该使用的排序顺序传递给该方法。
  43. privatevoidaddItem(Stringstring){
  44. ContentValuesvalues=newContentValues();
  45. values.put(TIME,System.currentTimeMillis());
  46. values.put(TITLE,string);
  47. getContentResolver().insert(CONTENT_URI,values);
  48. }
  49. //没有了对getWriteableDatabase()的调用,对insertOrThrow的调用替换成了getContentResolver().insert(CONTENT_URI,values)
  50. //我们使用了一个URI而不是用数据库句柄。
  51. }


下面就是实现ContentProvider

ContentProvider是一个类似于Activity的高级对象,需要向系统进行声明。因此,实现ContentProvider的第一步是将其添加到AndroidManifest.xml文件中的<activity>标签之前。

其中android:name是类名,android:authorities是在内容URI中使用的字符串。接下来创建我们自己的ContentProvider类,为继承类。ContentProvider创建后就会被调用:public boolean onCreate()ContentProvider类中有6个继承而来的方法,需要实现:

具体来说需要实现ContentProvider 类中的6个抽象方法。
Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):将查询的数据以Cursor 对象的形式返回。
Uri insert(Uri uri, ContentValues values):向 Content Provider中插入新数据记录,ContentValues 为数据记录的列名和列值映射。
int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):更新Content Provider中已存在的数据记录。

int delete(Uri uri, String selection, String[] selectionArgs):从Content Provider中删除数据记录。

String getType(Uri uri):返回Content Provider中的数据( MIME )类型。

boolean onCreate():当 Content Provider 启动时被调用。

定义一个 URI 类型的静态常量,命名为CONTENT_URI。 必须为该常量对象定义一个唯一的URI字符串,一般的做法是将 ContentProvider子类的全称类名作为URI字符串。

定义每个字段的列名,如果采用的数据库存储系统为SQLite 数据库,数据表列名可以采用数据库中表的列名。不管数据表中有没有其他的唯一标识一个记录的字段,都应该定义一个"_id"字段 来唯一标识一个记录。模式使用 "INTEGER PRIMARY KEY AUTOINCREMENT" 自动更新 一般将这些列名字符串定义为静态常量, 如"_id"字段名定义为一个名为"_ID" 值为 "_id" 的静态字符串对象。

创建好的一个Content Provider必须在AndroidManifest.xml中声明。

<provider android:name=".ItemsProvider"

android:authorities="com.blueeagle" />

其中name属性为ContentProvider 子类的全称类名,authorities 属性唯一标识了一个ContentProvider。还可以通过 setReadPermission() 和 setWritePermission() 来设置其操作权限。当然也可以再上面的 xml中加入 android:readPermission 或者 android: writePermission属性来控制其权限。
注意:因为ContentProvider可能被不同的进程和线程调用,所以这些方法必须是线程安全的。

然后需要使用UriMatcher,用于匹配Uri。
用法如下:
首先把需要匹配Uri路径全部给注册上:

对于Uri:

什么是URI?将其分为A,B,C,D 4个部分:

A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;"content://"

B:URI的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的 类名。这个标识在 元素的 authorities属性中说明:一般是定义该ContentProvider的包.类的名称 ;"content://hx.android.text.myprovider"

C:路径,不知道是不是路径,通俗的讲就是你要操作的数据库中表的名字,或者你也可以自己定义,记得在使用的时候保持一致就ok了;"content://hx.android.text.myprovider/tablename"

D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部; "content://hx.android.text.myprovider/tablename/#" #表示数据id

注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,例如匹配content://com.blueeagle路径,返回的匹配码为1。

//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

//添加需要匹配的uri,如果匹配就会返回匹配码
//如果match()方法匹配content://com.blueeagle路径,返回匹配码为1
sUriMatcher.addURI(“content://com.blueeagle”, “HelloSQLite”, 1);

//如果match()方法匹配content://com.blueeagle/ ***路径,返回匹配码为2
//#号为通配符
sUriMatcher.addURI(“content://com.blueeagle”, “HelloSQLite/#”, 2);

switch(sUriMatcher.match(Uri.parse("content://com.blueeagle /***"))) {
case 1 break;
case 2 break;
default:
//不匹配 break;
}

自定义的contentprovider如下:

ItemsProvider.java

[java] view plain copy
  1. packagecom.blueeagle;
  2. /*
  3. *Android开发之数据保存技术(一)
  4. *ItemsProvider.java
  5. *Createdon:2011-8-16
  6. *Author:blueeagle
  7. *Email:liujiaxiang@gmail.com
  8. */
  9. importandroid.content.ContentProvider;
  10. importandroid.content.ContentUris;
  11. importandroid.content.ContentValues;
  12. importandroid.content.UriMatcher;
  13. importandroid.database.Cursor;
  14. importandroid.database.sqlite.SQLiteDatabase;
  15. importandroid.net.Uri;
  16. importandroid.text.TextUtils;
  17. importstaticcom.blueeagle.Constants.CONTENT_URI;
  18. importstaticcom.blueeagle.Constants.TABLE_NAME;
  19. importstaticcom.blueeagle.Constants.AUTHORITY;
  20. importstaticandroid.provider.BaseColumns._ID;
  21. publicclassItemsProviderextendsContentProvider{
  22. privatestaticfinalintITEMS=1;
  23. privatestaticfinalintITEMS_ID=2;
  24. /**TheMIMEtypeofadirectoryofitems*/
  25. privatestaticfinalStringCONTENT_TYPE
  26. ="vnd.android.cursor.dir/vnd.com.blueeagle";
  27. /**TheMIMEtypeofasingleitem*/
  28. privatestaticfinalStringCONTENT_ITEM_TYPE
  29. ="vnd.android.cursor.item/vnd.com.blueeagle";
  30. privateMySQLitemyDataBase;
  31. privateUriMatchermyUriMatcher;
  32. @Override
  33. publicbooleanonCreate(){
  34. myUriMatcher=newUriMatcher(UriMatcher.NO_MATCH);
  35. myUriMatcher.addURI(AUTHORITY,"HelloSQLite",ITEMS);
  36. myUriMatcher.addURI(AUTHORITY,"HelloSQLite/#",ITEMS_ID);
  37. myDataBase=newMySQLite(getContext());
  38. returntrue;
  39. }
  40. @Override
  41. publicintdelete(Uriuri,Stringselection,
  42. //TODOAuto-generatedmethodstub
  43. String[]selectionArgs){
  44. SQLiteDatabasedb=myDataBase.getWritableDatabase();
  45. intcount;
  46. switch(myUriMatcher.match(uri)){
  47. caseITEMS:
  48. count=db.delete(TABLE_NAME,selection,selectionArgs);
  49. break;
  50. caseITEMS_ID:
  51. longid=Long.parseLong(uri.getPathSegments().get(1));
  52. count=db.delete(TABLE_NAME,appendRowId(selection,id),
  53. selectionArgs);
  54. break;
  55. default:
  56. thrownewIllegalArgumentException("UnknownURI"+uri);
  57. }
  58. //Notifyanywatchersofthechange
  59. getContext().getContentResolver().notifyChange(uri,null);
  60. returncount;
  61. }
  62. @Override
  63. publicStringgetType(Uriuri){
  64. //TODOAuto-generatedmethodstub
  65. switch(myUriMatcher.match(uri)){
  66. caseITEMS:
  67. returnCONTENT_TYPE;
  68. caseITEMS_ID:
  69. returnCONTENT_ITEM_TYPE;
  70. default:
  71. thrownewIllegalArgumentException("UnknownURI"+uri);
  72. }
  73. }
  74. @Override
  75. publicUriinsert(Uriuri,ContentValuesvalues){
  76. //TODOAuto-generatedmethodstub
  77. SQLiteDatabasedb=myDataBase.getWritableDatabase();
  78. //Validatetherequesteduri
  79. if(myUriMatcher.match(uri)!=ITEMS){
  80. thrownewIllegalArgumentException("UnknownURI"+uri);
  81. }
  82. //Insertintodatabase
  83. longid=db.insertOrThrow(TABLE_NAME,null,values);
  84. //Notifyanywatchersofthechange
  85. UrinewUri=ContentUris.withAppendedId(CONTENT_URI,id);
  86. getContext().getContentResolver().notifyChange(newUri,null);
  87. returnnewUri;
  88. }
  89. @Override
  90. publicCursorquery(Uriuri,String[]projection,
  91. Stringselection,String[]selectionArgs,StringorderBy){
  92. //TODOAuto-generatedmethodstub
  93. if(myUriMatcher.match(uri)==ITEMS_ID){
  94. longid=Long.parseLong(uri.getPathSegments().get(1));
  95. selection=appendRowId(selection,id);
  96. }
  97. //Getthedatabaseandrunthequery
  98. SQLiteDatabasedb=myDataBase.getReadableDatabase();
  99. Cursorcursor=db.query(TABLE_NAME,projection,selection,
  100. selectionArgs,null,null,orderBy);
  101. //Tellthecursorwhaturitowatch,soitknowswhenits
  102. //sourcedatachanges
  103. cursor.setNotificationUri(getContext().getContentResolver(),
  104. uri);
  105. returncursor;
  106. }
  107. privateStringappendRowId(Stringselection,longid){
  108. //TODOAuto-generatedmethodstub
  109. return_ID+"="+id
  110. +(!TextUtils.isEmpty(selection)
  111. ?"AND("+selection+')'
  112. :"");
  113. }
  114. @Override
  115. publicintupdate(Uriuri,ContentValuesvalues,Stringselection,
  116. String[]selectionArgs){
  117. //TODOAuto-generatedmethodstub
  118. SQLiteDatabasedb=myDataBase.getWritableDatabase();
  119. intcount;
  120. switch(myUriMatcher.match(uri)){
  121. caseITEMS:
  122. count=db.update(TABLE_NAME,values,selection,
  123. selectionArgs);
  124. break;
  125. caseITEMS_ID:
  126. longid=Long.parseLong(uri.getPathSegments().get(1));
  127. count=db.update(TABLE_NAME,values,appendRowId(
  128. selection,id),selectionArgs);
  129. break;
  130. default:
  131. thrownewIllegalArgumentException("UnknownURI"+uri);
  132. }
  133. //Notifyanywatchersofthechange
  134. getContext().getContentResolver().notifyChange(uri,null);
  135. returncount;
  136. }
  137. }


总结一下,创建一个新的内容提供器。

1.通过扩展抽象类ContentProvider可以创建新的内容提供器。重写onCreate方法来打开或者初始化将要使用这个新的提供器来提供底层数据源。

2.还应该提供那些用来返回指向这个提供器的完整的URI的公共静态CONTENT_URI变量。提供器之间的内容URI应该是唯一的,所以最好的做法是使URI路径以包名为基础。

定义一个内容提供器URI一般的形式为:

content://com.pakagename/datapath

例如:content://com.blueeagle/items

或者:content://com.blueeagle./items/3

内容URI可以表示为这两种形式中的任意一种形式。前面的一种URI表示对那种类型中所有的值的请求,后面附加一个/3的表示对一条记录的请求(这里请求的是记录3)。这两种形式来访问提供器都是可行的。

完成这项工作最简单的方式是使用一个UriMatcher。当通过内容解析器来访问内容提供器的时候,可以配置UriMathcer来解析URI以确定它们的形式。就像前文说的那样。

源地址:http://blog.csdn.net/redoffice/article/details/6695345

更多相关文章

  1. android 使用Intent传递数据之静态变量
  2. Android 数据存储之SharedPreferences存储小记
  3. Android -SQLite数据库存储
  4. Android 获取未读短信同时,一并获取该短信内容的方法
  5. Android EditText属性介绍及监听内容变化
  6. android直接用v4l2采集图片数据
  7. Android之从网络中获取数据并返回客户端的两种方式:XML格式返回
  8. android应用安全——数据安全
  9. 在 Android 应用程序中使用 Internet 数据

随机推荐

  1. 居中对齐
  2. Android(安卓)Contextual Menus之二:conte
  3. 2010.12.10——— android 定位跟踪
  4. ?android:attr/属性 与 ?android:属性
  5. 【转】android manifest.xml中元素含义
  6. Android(安卓)ProgressBar进度条
  7. Android(安卓)OpenGL ES学习笔记之实现Op
  8. Android(安卓)recyclerview实现查看更多/
  9. android 获取手机通讯录信息
  10. Activity背景色为透明的2种方法