在Android中,content provider是一个特殊的存储数据的类型,它提供了一套标准的接口用来获取以及操作数据。并且,android自身也提供了几个现成的content provider:Contacts, Browser, CallLog, Settings, MediaStore. 例如访问通讯录使用People.CONTENT_URI。
要实现应用程序之间的数据共享,需要在数据提供方实现一个ContentProvider的继承类,重写query() , insert() , update() , delete()等方法,然后创建一个Uri,并在Manifest.xml中声明provider,设置android:exported = true;在另一个应用程序中通过使用Content Resolver和该Uri来实现查询等等操作,如查询:getContentResolver.query(Uri , projection , selection , selectionArgs , orderBy)。
什么是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
UriMatcher:用于匹配Uri,它的用法如下:
1.首先把你需要匹配Uri路径全部给注册上,如下: //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。 UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); //如果match()方法匹配content://com.changcheng.sqlite.provider.contactprovider/contact路径,返回匹配码为1 uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact”, 1);//添加需要匹配uri,如果匹配就会返回匹配码 //如果match()方法匹配 content://com.changcheng.sqlite.provider.contactprovider/contact/230路径,返回匹配码为2 uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2);//#号为通配符
2.注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用 addURI()方法传入的第三个参数,假设匹配 content://com.changcheng.sqlite.provider.contactprovider/contact路径,返回的匹配码为1。
ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
· withAppendedId(uri, id)用于为路径加上ID部分
· parseId(uri)方法用于从路径中获取ID部分
下面看一个例子:
这个例子是这样的:NotePad提供Uri,NotePadProvider是一个ContentProvider的子类,这是数据提供方,提供了一些访问私有数据的访问接口;AccessProviderActivity是另一个程序,是数据访问端。注意权限问题。
public final class NotePad {
public static final String AUTHORITY = "com.wen.pad.notepad";
// This class cannot be instantiated
private NotePad() {
}
public static final class Notes implements BaseColumns {
// This class cannot be instantiated
private Notes() {}
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes");
/**
* The MIME type of {@link #CONTENT_URI} providing a directory of notes.
*/
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.note";
/**
* The MIME type of a {@link #CONTENT_URI} sub-directory of a single
* note.
*/
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.note";
/**
* The default sort order for this table
*/
public static final String DEFAULT_SORT_ORDER = "modified DESC";
/**
* Column name for the title of the note
* <P>Type: TEXT</P>
*/
public static final String TITLE = "title";
/**
* Column name of the note content
* <P>Type: TEXT</P>
*/
public static final String NOTE = "note";
/**
* Column name for the creation timestamp
* <P>Type: INTEGER (long from System.curentTimeMillis())</P>
*/
public static final String CREATEDDATE = "created";
/**
* Column name for the modification timestamp
* <P>Type: INTEGER (long from System.curentTimeMillis())</P>
*/
public static final String MODIFIEDDATE = "modified";
}
}
public class NotePadProvider extends ContentProvider {
private static final String TAG = "NotePadProvider";
private static final String DATABASE_NAME = "note_pad.db";
private static final int DATABASE_VERSION = 1;
private static final String NOTES_TABLE_NAME = "notes";
private static HashMap<String, String> sNotesProjectionMap;
private static final int NOTES = 1;
private static final int NOTE_ID =2;
private static final UriMatcher sUriMatcher ;
private DatabaseHelper mOpenHelper;
private static final String CREATE_TABLE = "CREATE TABLE "+NOTES_TABLE_NAME
+ "(" + Notes._ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ Notes.TITLE
+ " TEXT,"
+ Notes.NOTE
+ " TEXT,"
+ Notes.CREATEDDATE
+ " INTEGER,"
+ NotePad.Notes.MODIFIEDDATE
+ " INTEGER" + ")";
static{
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);
sNotesProjectionMap = new HashMap<String,String>();
sNotesProjectionMap.put(Notes._ID, Notes._ID);
sNotesProjectionMap.put(Notes.TITLE, Notes.TITLE);
sNotesProjectionMap.put(Notes.NOTE, Notes.NOTE);
sNotesProjectionMap.put(Notes.CREATEDDATE, Notes.CREATEDDATE);
sNotesProjectionMap.put(Notes.MODIFIEDDATE, Notes.MODIFIEDDATE);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
if(sUriMatcher.match(uri)!=NOTES){
throw new IllegalArgumentException("Unknown URI "+uri);
}
ContentValues cv;
if(values != null)
{
cv = new ContentValues(values);
}
else
{
cv = new ContentValues();
}
Long now = Long.valueOf(System.currentTimeMillis());
if(cv.containsKey(NotePad.Notes.CREATEDDATE) == false)
{
cv.put(NotePad.Notes.CREATEDDATE,now);
}
if(cv.containsKey(NotePad.Notes.MODIFIEDDATE) == false)
{
cv.put(NotePad.Notes.MODIFIEDDATE, now);
}
if(cv.containsKey(NotePad.Notes.TITLE) == false)
{
Resources r = Resources.getSystem();
cv.put(NotePad.Notes.TITLE, r.getString(android.R.string.untitled));
}
if(cv.containsKey(NotePad.Notes.NOTE) == false)
{
cv.put(NotePad.Notes.NOTE, "");
}
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, cv);
if(rowId > 0)
{
Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId);
return noteUri;
}
throw new SQLException("Failed to insert row into " + uri);
}
@Override
public boolean onCreate() {
// TODO Auto-generated method stub
mOpenHelper = new DatabaseHelper(this.getContext());
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
switch(sUriMatcher.match(uri)){
case NOTES:
qb.setTables(NOTES_TABLE_NAME);
qb.setProjectionMap(sNotesProjectionMap);
break;
case NOTE_ID:
qb.setTables(NOTES_TABLE_NAME);
qb.setProjectionMap(sNotesProjectionMap);
qb.appendWhere(Notes._ID+"="+uri.getPathSegments().get(1));
default:
throw new IllegalArgumentException("Unknown URI"+uri);
}
String orderBy;
if(TextUtils.isEmpty(sortOrder)){
orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;
}
else{
orderBy = sortOrder;
}
SQLiteDatabase db = mOpenHelper.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) {
// TODO Auto-generated method stub
return 0;
}
private static class DatabaseHelper extends SQLiteOpenHelper
{
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
// TODO Auto-generated constructor stub
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL(CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
}
manifest.xml中要添加provider
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wen.pad"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<permission android:name="com.wen.pad.NOTEPAD_READ_PERMISSION"/> <!-- 自定义的permission需先在这里声明 -->
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<provider android:name=".NotePadProvider"
android:authorities="com.wen.pad.notepad"
android:exported="true" <!-- 设置成true才能访问 -->
android:readPermission="com.wen.pad.NOTEPAD_READ_PERMISSION"/> <!-- 设置读permission,其他程序要用这个provider,必须先use这个permission -->
<activity
android:name=".NotePadActivity"
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"/>
</intent-filter>
<intent-filter >
<data android:mimeType="vnd.android.cursor.item/vnd.google.note"/>
</intent-filter>
</activity>
</application>
</manifest>
访问程序(另一程序):读取数据,然后在Toast中显示
public class AccessProviderActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
displayNote();
}
private void displayNote()
{
String columns[] = new String[]{"_id",
"title",
"note",
"created",
"modified"
};
Uri myUri = Uri.parse("content://com.wen.pad.notepad/notes");
Cursor cur = this.getContentResolver().query(myUri, columns, null, null, null);
// Cursor cur = this.managedQuery(myUri, columns, null, null, null);
if(cur.moveToFirst()){
String id = null;
String title = null;
do{
id = cur.getString(cur.getColumnIndex("_id"));
title = cur.getString(cur.getColumnIndex("title"));
Toast.makeText(this, "TITLE: "+id+" NOTE: "+title, Toast.LENGTH_LONG).show();
}while(cur.moveToNext());
}
}
}
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wen.access"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="com.wen.pad.NOTEPAD_READ_PERMISSION"/> <!--这里声明使用这个permission才能有权限访问NotePadProvider-->
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".AccessProviderActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>