ContentProvider 之使用

应用声景:

当一个android的开发中当程序之间需要数据交互的时候,使用ContentProvider是一个很好的选择。

ContentProvider对外只是提供了一个借口,隐藏了细节,只需要一个ContentResolver对象就可以调用 ContentProvider的函数。

基本步骤如下:

1、写一个类继承ContentProvider,override里面的函数,比如insert,delete等。在 AndroidManifest.xml 文件中进行注册,

       格式如下:

     <provider android:name="类名"
               android:authorities="Uri字符串">
     </provider>
     类名,就是你自己写的类名称。Uri字符串,是一个特征字符串,就相当于ContentProvider的身份证了。
2、得到一个Uri对象,Uri实际上应该是这种格式:content://Uri字符串,所以我们可以得到一个String test="content://"+"Uri
     字符串"(必须和mainfest中相同),现在可以用static函数 Uri.parse(test)得到这个对象了。

3、得到一个ContentResolver对象,在contex或其子类(例如activity)可以直接调用getContentResolver函数。

ok,现在就可以直接使用了

下面举例说明:
对于使用 ContentProvider 来说,最好对于编辑或修改(Insert/delete)或者啥的由本身应用完成,不应该交给其它应用权限,而对于查询可以提供,这样子能保证只有一个用户写入,多个用户进行查询,否则数据库数据写完了就完蛋了。记得还是做好数据库的备份。


下面以实例说明一下用法:

首先定义数据库字段:

package com.test.contentprovider;

import android.net.Uri;
import android.provider.BaseColumns;

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

	private NotePad() {
	}

	// 定义基本字段
	public static final class Notes implements BaseColumns {
		private Notes() {
		}

		/* 外部访问的重要Uri值 */
		public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes");

		// 新的MIME类型-多个
		public static final String CONTENT_TYPE = "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 TITLE = "title";
		public static final String NOTE = "note";
		public static final String CREATEDDATE = "created-date";
		public static final String MODIFIEDDATE = "modified-date";
	}
}

然后定现ContentProvider:

package com.test.contentprovider;

import java.util.HashMap;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;

import com.test.contentprovider.NotePad.Notes;

public class NotePadProvider extends ContentProvider
{
	// 数据库名
	private static final String				DATABASE_NAME		= "note_pad.db";
	private static final int				DATABASE_VERSION	= 2;

	// 表名
	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;
	
	//创建表SQL语句
	private static final String				CREATE_TABLE="CREATE TABLE " 
														+ NOTES_TABLE_NAME 
														+ " (" + Notes._ID 
														+ " INTEGER PRIMARY KEY," 
														+ Notes.TITLE 
														+ " TEXT," 
														+ Notes.NOTE 
														+ " TEXT,"
														+ Notes.CREATEDDATE 
														+ " INTEGER," 
														+ 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);
	}

	private static class DatabaseHelper extends SQLiteOpenHelper {
		// 构造函数-创建数据库
		DatabaseHelper(Context context) {
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}

		// 创建表
		@Override
		public void onCreate(SQLiteDatabase db) {
			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 boolean onCreate()
	{
		mOpenHelper = new DatabaseHelper(getContext());
		return true;
	}

	//查询操作
	@Override
	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
	{
		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));
				break;

			default:
				throw new IllegalArgumentException("Unknown URI " + uri);
		}

		SQLiteDatabase db = mOpenHelper.getReadableDatabase();
		Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, null);
		c.setNotificationUri(getContext().getContentResolver(), uri);
		return c;
	}
	
	/* 如果有自定义类型,必须实现该方法  */
	@Override
	public String getType(Uri uri) {
		switch (sUriMatcher.match(uri)) {
		case NOTES:
			return Notes.CONTENT_TYPE;

		case NOTE_ID:
			return Notes.CONTENT_ITEM_TYPE;

		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
	}
	
	//插入数据库
	@Override
	public Uri insert(Uri uri, ContentValues initialValues) {
		ContentValues values;
		if (sUriMatcher.match(uri) != NOTES) {
			throw new IllegalArgumentException("Unknown URI " + uri);
		}

		if (initialValues != null) {
			values = new ContentValues(initialValues);
		} else {
			values = new ContentValues();
		}
		Long now = Long.valueOf(System.currentTimeMillis());

		if (values.containsKey(NotePad.Notes.CREATEDDATE) == false) {
			values.put(NotePad.Notes.CREATEDDATE, now);
		}
		if (values.containsKey(NotePad.Notes.MODIFIEDDATE) == false) {
			values.put(NotePad.Notes.MODIFIEDDATE, now);
		}
		if (values.containsKey(NotePad.Notes.TITLE) == false) {
			Resources r = Resources.getSystem();
			values.put(NotePad.Notes.TITLE,
					r.getString(android.R.string.untitled));
		}
		if (values.containsKey(NotePad.Notes.NOTE) == false) {
			values.put(NotePad.Notes.NOTE, "");
		}
		
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values);
		if (rowId > 0) {
			Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI,rowId);
			getContext().getContentResolver().notifyChange(noteUri, null);
			return noteUri;
		}
		throw new SQLException("Failed to insert row into " + uri);
	}
	
	//删除数据
	@Override
	public int delete(Uri uri, String where, String[] whereArgs)
	{
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		int count;
		switch (sUriMatcher.match(uri)) {
		case NOTES:
			count = db.delete(NOTES_TABLE_NAME, where, whereArgs);
			break;
		case NOTE_ID:
			String noteId = uri.getPathSegments().get(1);
			count = db.delete(NOTES_TABLE_NAME, Notes._ID + "=" + noteId + 
					(!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
		return count;
	}
	
	//更新数据
	@Override
	public int update(Uri uri, ContentValues values, String where, String[] whereArgs)
	{
		int count;
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		switch (sUriMatcher.match(uri)) {
		case NOTES:
			count = db.update(NOTES_TABLE_NAME, values, where, whereArgs);
			break;

		case NOTE_ID:
			String noteId = uri.getPathSegments().get(1);
			count = db.update(NOTES_TABLE_NAME, values, Notes._ID + "=" + noteId + 
					(!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
			break;
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
		return count;
	}
}

最后实现测试代码:

package com.test.contentprovider;

import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.Toast;
import com.test.contentprovier.R;

public class Activity01 extends Activity
{
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		/* 插入数据 */
		ContentValues values = new ContentValues();
		values.put(NotePad.Notes.TITLE, "title1");
		values.put(NotePad.Notes.NOTE, "NOTENOTE1");
		getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);

		values.clear();
		values.put(NotePad.Notes.TITLE, "title2");
		values.put(NotePad.Notes.NOTE, "NOTENOTE2");
		getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);

		/* 显示 */
		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 cur = managedQuery(myUri, columns, null, null, null);
		if (cur.moveToFirst()) {
			String id = null;
			String title = null;
			do {
				id = cur.getString(cur.getColumnIndex(NotePad.Notes._ID));
				title = cur.getString(cur.getColumnIndex(NotePad.Notes.TITLE));
				Toast toast = Toast.makeText(this, "TITLE:" + id + "NOTE:"
						+ title, Toast.LENGTH_LONG);
				toast.setGravity(Gravity.TOP | Gravity.CENTER, 0, 40);
				toast.show();
			} while (cur.moveToNext());
		}
	}
}

后面为了提供给其它应用程序使用,记着注册:

AndroidManifest.xml 中添加:

<provider android:name="com.test.contentprovider.NotePadProvider" 
     android:authorities="com.google.provider.NotePad">

</provider>


其访问的Uri 为:

NotePad.Notes.CONTENT_URI 

/* 外部访问的重要Uri值 */
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes");


还有一点需要注意:

MIME类型 :MIME:全称Multipurpose Internet Mail Extensions,多功能Internet 邮件扩充服务。它是一种多用途网际邮件扩充协议,在1992年最早应用于电子邮件系统,但后来也应用到浏览器。MIME类型就是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。

其实,MIME类型其实就是一个字符串,中间有一个 “/” 来隔开,“/”前面的部分是系统识别的部分,就相当于我们定义一个变量时的变量数据类型,通过这个“数据类型”,系统能够知道我们所要表示的是个什么东西。至于 “/” 后面的部分就是我们自已来随便定义的“变量名”了。


Uri : 通用资源标志符(Universal Resource Identifier, 简称"URI")

Uri代表要操作的数据,Android上可用的每种资源 - 图像、视频片段等都可以用Uri来表示。

 

URI一般由三部分组成:

访问资源的命名机制。 

存放资源的主机名。 

资源自身的名称,由路径表示。 


Android的Uri由以下三部分组成: "content://"、数据的路径、标示ID(可选)

举些例子,如: 

所有联系人的Uri: content://contacts/people

某个联系人的Uri: content://contacts/people/5

所有图片Uri: content://media/external

某个图片的Uri:content://media/external/images/media/4

Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris


总结: 

--常量 UriMatcher.NO_MATCH 表示不匹配任何路径的返回码

--# 号为通配符

--* 号为任意字符


你可能感兴趣的:(ContentProvider 之使用)