Android数据共享机制ContentProvider
来源:互联网 发布:贵州广电网络员工待遇 编辑:程序博客网 时间:2024/05/11 21:05
一、简介
Android使用一种称为ContentProvider的概念来将数据抽象为服务,这种内容提供程序的理念看起来像启用了REST的数据提供程序。
要从ContentProvider检索数据或将数据保存到ContentProvider,需要使用一组类似REST的URI。例如,要从封装图书数据库的ContentProvider获取一组图书,需要使用以下形式的URI:
二、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中进行。如:
1、Android内容URI的结构
Android中的内容URI类似于Http URL,但他们以content://开头具有一下通用形式:
就像网站返回给指定URI的MIME类型一样,ContentProvider也负责返回给URI的MIME类型。MIME类型包括两部分:类型和子类型。如:
3、使用URI读取数据
要从ContentProvider获取数据,需要使用该ContentProvider提供的URI。
如下:为从联系人提供程序获取单行联系人信息
在使用Android游标前,先了解一些关于游标的的知识。
游标是一个行集合;
读取数据之前,需要使用moveToFirst(),因为游标放在第一行之前;
需要知道列的名称和类型;
所有字段访问都基于列编号,所以必须首先将列名称转换为列编号;
游标可以随意移动;
可以使用游标获取行计数;
使用while循环导航游标:
ContentProvider提供两种方式来传递where子句:
通过URI;
android使用ContentValues来保存将插入的单一记录的值,要插入记录,由android.content.ContentResolver使用URI插入记录。下面是个例子:
更新类似插入,方法签名为:
我们将按如下流程来实现:
(1)计划数据库、URI、列名称,创建元数据类来定义所有的这些元数据元素的常量;
(2)扩展抽象类ContentProvider
(3)实现方法:query、insert、update、delete和getType
(4)在描述文件中注册提供程序
具体代码如下:
布局文件:
Android使用一种称为ContentProvider的概念来将数据抽象为服务,这种内容提供程序的理念看起来像启用了REST的数据提供程序。
要从ContentProvider检索数据或将数据保存到ContentProvider,需要使用一组类似REST的URI。例如,要从封装图书数据库的ContentProvider获取一组图书,需要使用以下形式的URI:
content://com.android.book.BookProvider/books要从图书数据库获得指定图书(如编号为:88图书),则要使用以下类似URI:
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中进行。如:
<provider android:name="BookProvider" android:authorities="com.myCompany.BookProvider"/>在进行了授权后,ContentProvider就拥有了以授权前缀开头的URI:
content://com.myCompany.BookProvider/注意:Android内置的ContentProvider可能没有完全限定的授权名,只有在使用第三方提供的时才使用完全限定名。这也就是为什么有时候仅使用Contacts来引用联系人ContentProvider。
1、Android内容URI的结构
Android中的内容URI类似于Http URL,但他们以content://开头具有一下通用形式:
Content://*/*/或content://authority-name/path-segment1/path-segment2/etc......2、Android MIME类型的结构
就像网站返回给指定URI的MIME类型一样,ContentProvider也负责返回给URI的MIME类型。MIME类型包括两部分:类型和子类型。如:
text/htmltext/csstext/xmlapplication/pdfapplication/vnd.ms-excel类型和子类型对于他们所表示的内容必须是唯一的,且如果类型和子类型不是标准的,则需要在他们前面加上vnd。
3、使用URI读取数据
要从ContentProvider获取数据,需要使用该ContentProvider提供的URI。
如下:为从联系人提供程序获取单行联系人信息
Uri baseUri = Contacts.People.CONTENT_URI;uri myPersonUri = baseUri.withAppendedPath(Contacts.People.CONTENT_URI,"80");Cursor cur = manageQuery(myPersonUri,null,null,null);在上面的基础上我们来看看,如何获取一个游标,这个游标包含来自contactsContentProvider的People表的一组特定的列。
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循环导航游标:
if (cur.moveToFirst == false){ return;}int nameColumnIndex = cur.getColumnIndex(People.NAME);String name = cur.getString(nameColumnIndex);while (cur.moveToNext()){ //获取属性值}使用for循环导航游标
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;
String noteUri = "content://com.google.provider.NotePad.notes.80";Cursor managedCursor = managedQuery(noteUri, projection,//返回的列 null,//where子句 Contacts.People.NAME + "ASC"//排序方式);通过String子句与一组可替换的字符串数组参数的组合。
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插入记录。下面是个例子:
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、更新和删除
更新类似插入,方法签名为:
int numberOfRowsUpdated = activity.getContentResolver().update( Uri uri, ContentValues values, String whereClause, String[] selectionArgs);类似的删除的方法为:
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)在描述文件中注册提供程序
具体代码如下:
布局文件:
<?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)
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)
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
<?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>
运行结果如下图所示:
- Android数据共享机制ContentProvider
- Android数据共享机制ContentProvider
- contentprovider数据共享机制
- contentprovider数据共享机制
- Android -----数据共享ContentProvider
- 再探Android多应用间数据共享机制,自定义ContentProvider
- android ContentProvider共享数据方法
- android 使用ContentProvider共享数据
- Android之ContentProvider(数据共享)
- android数据存储:ContentProvider数据共享
- Android数据存储—ContentProvider共享数据
- Android 应用程序之间数据共享—ContentProvider
- Android 应用程序之间数据共享—ContentProvider
- Android 应用程序之间数据共享—ContentProvider
- Android 应用程序之间数据共享—ContentProvider
- Android 应用程序之间数据共享—ContentProvider
- Android 应用程序之间数据共享—ContentProvider
- Android 应用程序之间数据共享—ContentProvider
- logback logback.xml常用配置详解
- FastReport FAQ
- 多线程:如何在调用线程时传递参数总结
- 网站不被搜索引擎收录的关键原因分析14条
- Linux下安装Apache
- Android数据共享机制ContentProvider
- zen-cart 如何增加一个可下载的商品
- 菜鸟从零开始的第一个应用上线记(二)
- Zencart 程序网站的优化
- 超链接文本的下划线去不掉 CSS
- jQuery实现DIV层淡入淡出的拖动效果
- 黑马程序员_MyEclipse快捷键
- android 设置背景图片 xml的background和java的getDrawable()
- win7删除右键菜单的操作