您的位置:首页 > 移动开发 > Android开发

Android数据共享机制ContentProvider

2012-08-20 17:20 477 查看
转自:http://www.2cto.com/kf/201205/129963.html

Android中的Content
provider机制可支持在多个应用中存储和读取数据。这也是跨应用共享数据的唯一方式。在android系统中,没有一个公共的内存区域,供多个应用共享存储数据。
Android提供了一些主要数据类型的Content provider,比如音频、视频、图片和私人通讯录等。可在android.provider包下面找到一些android提供的Content provider。可以获得这些Content provider,查询它们包含的数据,当然前提是已获得适当的读取权限。
如果想公开自己的数据,那么可有两种办法:



创建自己的Content provider,需要继承ContentProvider类;

如果你的数据和已存 在的Content provider数据结构一致,可以将数据写到已存在的Content provider中,当然前提是获取写该Content provider的权限。比如把OA中的成员通讯信息加入到系统的联系人Content provider中。

Content provider基础所有Content provider都需要实现相同的接口用于查询Content provider并返回数据,也包括增加、修改和删除数据。

一、简介

Android使用一种称为ContentProvider的概念来将数据抽象为服务,这种内容提供程序的理念看起来像启用了REST的数据提供程序。

要从ContentProvider检索数据或将数据保存到ContentProvider,需要使用一组类似REST的URI。例如,要从封装图书数据库的ContentProvider获取一组图书,需要使用以下形式的URI:

[java]

content://com.android.book.BookProvider/books

要从图书数据库获得指定图书(如编号为:88图书),则要使用以下类似URI:

[java]

content://com.android.book.BookProvider/books/88

设备上的任何应用程序都可以通过这些URI来访问或操作数据,所以在应用程序之间的数据共享上ContentProvider扮演着非常主要的角色。

二、Android内置的ContentProvider

Android中存在大量的内置ContentProvider,他们记录在SDK的android.provider包中,如:

Browser

Calllog

Contacts

People

Phones

Photos

Groups

MediaStore

Audio

Albums

Artists

Playlists

Images

Video

Settings

其中顶级项数据库,较低级的项是表。所以Browser、CAllog,MediaStore和Settings都是封装为ContentProvider的独立SQLite数据库.这些数据库通常具有扩展名.db。仅能从实现包访问,任何来自外部的访问都要通过ContentProvider接口。

三、ContentProvider架构

与网站一样,设备上的每个ContentProvider都会使用字符串注册本身,这个字符串类似网站域名,但称为:授权(Authority)。授权的注册则AndroidManifest.xml中进行。如:

[java]

<provider android:name="BookProvider" android:authorities="com.myCompany.BookProvider"/>

在进行了授权后,ContentProvider就拥有了以授权前缀开头的URI:

[java]

content://com.myCompany.BookProvider/

注意:Android内置的ContentProvider可能没有完全限定的授权名,只有在使用第三方提供的时才使用完全限定名。这也就是为什么有时候仅使用Contacts来引用联系人ContentProvider。

1、Android内容URI的结构

Android中的内容URI类似于Http URL,但他们以content://开头具有一下通用形式:

[java]

Content://*/*/



content://authority-name/path-segment1/path-segment2/etc......

2、Android MIME类型的结构

就像网站返回给指定URI的MIME类型一样,ContentProvider也负责返回给URI的MIME类型。MIME类型包括两部分:类型和子类型。如:

[java]

text/html

text/css

text/xml

application/pdf

application/vnd.ms-excel

类型和子类型对于他们所表示的内容必须是唯一的,且如果类型和子类型不是标准的,则需要在他们前面加上vnd。

3、使用URI读取数据

要从ContentProvider获取数据,需要使用该ContentProvider提供的URI。

如下:为从联系人提供程序获取单行联系人信息

[java]

Uri baseUri = Contacts.People.CONTENT_URI;

uri myPersonUri = baseUri.withAppendedPath(Contacts.People.CONTENT_URI,"80");

Cursor cur = manageQuery(myPersonUri,null,null,null);

在上面的基础上我们来看看,如何获取一个游标,这个游标包含来自contactsContentProvider的People表的一组特定的列。

[java]

String[] projection = new String[]{

People._ID,

People.NAME,

People.NUMBER

};



Uri mContactsURi = Contacts.People.CONTENT_URI;

Cursor managedCursor = managedQuery(

projection,

null,

Contacts.People.NAME + "ASC"

);

4、使用游标

在使用Android游标前,先了解一些关于游标的的知识。

游标是一个行集合;

读取数据之前,需要使用moveToFirst(),因为游标放在第一行之前;

需要知道列的名称和类型;

所有字段访问都基于列编号,所以必须首先将列名称转换为列编号;

游标可以随意移动;

可以使用游标获取行计数;

使用while循环导航游标:

[java]

if (cur.moveToFirst == false){

return;

}

int nameColumnIndex = cur.getColumnIndex(People.NAME);

String name = cur.getString(nameColumnIndex);



while (cur.moveToNext()){

//获取属性值

}

使用for循环导航游标

[java]

int nameColumn = cur.getColumnIndex(People.NAME);

int ploneColumn = cur.getColumnIndex(People.NUMBER);



for(cur.moveToFirst();!cur.isAfterLast();cur.moveToNext()){

String name = cur.getString(nameColumn);

String phoneNumber = cur.getString(phoneColumn);

}

5、使用Where子句

ContentProvider提供两种方式来传递where子句:

通过URI;

[java]

String noteUri = "content://com.google.provider.NotePad.notes.80";

Cursor managedCursor = managedQuery(noteUri,

projection,//返回的列

null,//where子句

Contacts.People.NAME + "ASC"//排序方式

);

通过String子句与一组可替换的字符串数组参数的组合。

[java]

String noteUri = "content://com.google.provider.NotePad.notes";

Cursor managedCursor = managedQuery(noteUri,

projection,//返回的列

"_id=?",//where子句

new String[]{80},

Contacts.People.NAME + "ASC"//排序方式

);

6、插入记录

android使用ContentValues来保存将插入的单一记录的值,要插入记录,由android.content.ContentResolver使用URI插入记录。下面是个例子:

[java]

ContentValues values = new ContentValues();

values.put("title","new Note");

values.put("note","this is a new Note");

ContentResolver cr = activity.getContentResolver();

Uri uri = cr.insert(Notepad.Notes.CONTENT_URI,values);

7、更新和删除

更新类似插入,方法签名为:

[java]

int numberOfRowsUpdated = activity.getContentResolver().update(

Uri uri,

ContentValues values,

String whereClause,

String[] selectionArgs

);

类似的删除的方法为:

[java]

int numberOfRowsDeleted = activity.getContentResolver().delete(

Uri uri,

String whereClause,

String[] selectionArgs

);

8、下面我们自己实现一个ContentProvider,并进行CRUD操作;

我们将按如下流程来实现:

(1)计划数据库、URI、列名称,创建元数据类来定义所有的这些元数据元素的常量;

(2)扩展抽象类ContentProvider

(3)实现方法:query、insert、update、delete和getType

(4)在描述文件中注册提供程序

具体代码如下:

布局文件:

[java]

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<TextView

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="@string/hello"

/>

</LinearLayout>

元数据类:(NotePad.java)

[java]

public class NotePad {

//授权

public static final String AUTHORITY = "com.google.provider.NotePad";

private NotePad(){



}

public static final class Notes implements BaseColumns{

private Notes(){



}

//uri = "content://" + AUTHORITY + "/notes"

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



//新的MiMe类型-多个

public static final String CONTENT_ITEM = "vnd.android.cursor.dir/vnd.google.note";

//新的MiMe类型-单个

public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.note";



//排序方式

public static final String DEFAULT_SORT_ORDER = "modified DESC";



//字段

public static final String TITLE = "title";

public static final String NOTE = "note";

public static final String CREATEDDATE = "created";

public static final String MODIFIEDDATE = "modified";

}

}

扩展ContentProvider类(NotePadProvider.java)

[java]

public class NotePadProvider extends ContentProvider{

private static final String TAG = "NotePadProvider";



//数据库名

private static final String DATABASE_NAME = "notepad.db";

private static final int DATABASE_VERSION = 2;



//表名

private static final String TABLE_NAME = "notes";

private static HashMap<String,String> noteProjectionMap;

private static final int NOTES = 1;

private static final int NOTE_ID = 2;



//uri匹配器

private static final UriMatcher urimatcher;

private DatabaseHelper openHelper;

private static final String CREATE_TABLE = "CREATE TABLE "

+ TABLE_NAME

+ "(" +Notes._ID

+ " INTEGER PRIMARY KEY,"

+ Notes.TITLE + " TEXT,"

+ Notes.NOTE + " TEXT,"

+ Notes.CREATEDDATE + " INTEGER,"

+ Notes.MODIFIEDDATE + " INTEGER" + ")";

static{

urimatcher = new UriMatcher(UriMatcher.NO_MATCH);

urimatcher.addURI(NotePad.AUTHORITY, "notes",NOTES);

urimatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);



//列别名

noteProjectionMap = new HashMap<String,String>();

noteProjectionMap.put(Notes._ID,Notes._ID);

noteProjectionMap.put(Notes.TITLE, Notes.TITLE);

noteProjectionMap.put(Notes.NOTE, Notes.NOTE);

noteProjectionMap.put(Notes.CREATEDDATE, Notes.CREATEDDATE);

noteProjectionMap.put(Notes.MODIFIEDDATE,Notes.MODIFIEDDATE);

}



private static class DatabaseHelper extends SQLiteOpenHelper{

public DatabaseHelper(Context context){

super(context, DATABASE_NAME, null, DATABASE_VERSION);

}

//创建表

@Override

public void onCreate(SQLiteDatabase db) {

Log.i(TAG, CREATE_TABLE);

db.execSQL(CREATE_TABLE);

}

//更新数据库

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

db.execSQL("drop table if exists notes");

onCreate(db);

}



}

//删除数据

@Override

public int delete(Uri uri, String selection, String[] selectionArgs) {



return 0;

}

//获取MIME类型

@Override

public String getType(Uri uri) {

switch (urimatcher.match(uri)){

case NOTES:

return Notes.CONTENT_ITEM;

case NOTE_ID:

return Notes.CONTENT_ITEM_TYPE;

default:

throw new IllegalArgumentException("Unknow Uri" + uri);

}

}



@Override

public Uri insert(Uri uri, ContentValues values) {

if (urimatcher.match(uri) != NOTES){

throw new IllegalArgumentException("Unknow Uri" + uri);

}

ContentValues contentValues;

if (null != values){

contentValues = new ContentValues(values);

}else{

contentValues = new ContentValues();

}

Long now = Long.valueOf(System.currentTimeMillis());

if (!contentValues.containsKey(NotePad.Notes.CREATEDDATE)){

contentValues.put(NotePad.Notes.CREATEDDATE, now);

}

if (contentValues.containsKey(NotePad.Notes.MODIFIEDDATE) == false){

contentValues.put(NotePad.Notes.MODIFIEDDATE, now);

}

if (contentValues.containsKey(NotePad.Notes.TITLE) == false){

Resources r = Resources.getSystem();

contentValues.put(NotePad.Notes.TITLE, r.getString(android.R.string.untitled));

}

if (contentValues.containsKey(NotePad.Notes.NOTE) == false){

contentValues.put(NotePad.Notes.NOTE, "");

}

SQLiteDatabase db = openHelper.getWritableDatabase();

long rowId = db.insert(TABLE_NAME, Notes.NOTE, contentValues);

System.out.println(rowId);

if (rowId > 0){

Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId);

getContext().getContentResolver().notifyChange(noteUri, null);

return noteUri;

}

throw new SQLException("insert row into failed " + uri);

}



@Override

public boolean onCreate() {

openHelper = new DatabaseHelper(getContext());

return false;

}



@Override

public Cursor query(Uri uri, String[] projection, String selection,

String[] selectionArgs, String sortOrder) {

SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

switch (urimatcher.match(uri)){

case NOTES:

qb.setTables(TABLE_NAME);

qb.setProjectionMap(noteProjectionMap);

break;

case NOTE_ID:

qb.setTables(TABLE_NAME);

qb.setProjectionMap(noteProjectionMap);

qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1));

break;

default:

throw new IllegalArgumentException("Unknow Uri" + uri);

}

String orderBy;

if (TextUtils.isEmpty(sortOrder)){

orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;

}else{

orderBy = sortOrder;

}

SQLiteDatabase db = openHelper.getReadableDatabase();

Cursor cursor = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);

cursor.setNotificationUri(getContext().getContentResolver(),uri);

return cursor;

}



@Override

public int update(Uri uri, ContentValues values, String selection,

String[] selectionArgs) {

return 0;

}

}

活动类(ContentProviderTest.java)

public class ContentProviderTest extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);



//插入数据

ContentValues contentValues = new ContentValues();

contentValues.put(NotePad.Notes.TITLE, "title1");

contentValues.put(NotePad.Notes.NOTE, "NOTENOTE1");

getContentResolver().insert(NotePad.Notes.CONTENT_URI, contentValues);

contentValues.clear();

contentValues.put(NotePad.Notes.TITLE, "title2");

contentValues.put(NotePad.Notes.NOTE, "NOTENOTE2");

getContentResolver().insert(NotePad.Notes.CONTENT_URI, contentValues);

displayNote();

}

private void displayNote(){

String[] columns = new String[]{NotePad.Notes._ID

,NotePad.Notes.TITLE

,NotePad.Notes.NOTE

,NotePad.Notes.CREATEDDATE

,NotePad.Notes.MODIFIEDDATE};

Uri myUri = NotePad.Notes.CONTENT_URI;

Cursor cursor = managedQuery(myUri, columns, null, null, null);

if (cursor.moveToFirst()){

String id = null;

String title = null;

do{

id = cursor.getString(cursor.getColumnIndex(NotePad.Notes._ID));

title = cursor.getString(cursor.getColumnIndex(NotePad.Notes.TITLE));

Toast toast = Toast.makeText(this, "TITLE:" + id + "NOTES" + title, Toast.LENGTH_SHORT);

toast.setGravity(Gravity.TOP|Gravity.CENTER, 0, 40);

toast.show();

}while(cursor.moveToNext());

}

}

}

在描述文件中注册提供程序:AndroidManifest.xml

[html]

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.test.contentProvider"

android:versionCode="1"

android:versionName="1.0">



<application android:icon="@drawable/icon" android:label="@string/app_name">

<provider android:name="NotePadProvider"

android:authorities="com.google.provider.NotePad"/>

<activity android:name=".ContentProviderTest"

android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

<intent-filter>

<data android:mimeType="vnd.android.cursor.dir/vnd.google.note"></data>

</intent-filter>

<intent-filter>

<data android:mimeType="vnd.android.cursor.item/vnd.google.note"></data>

</intent-filter>

</activity>



</application>

</manifest>

运行结果如下图所示:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: