`
功夫小当家
  • 浏览: 183606 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

ContentProvider的使用

阅读更多

     ContentProvider在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对你应用中的数据进行添删改查。

     ContentProvider的优点:如果采用文件操作模式对外共享数据,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一,如:采用xml文件对外共享数据,需要xml解析才能读取数据;用sharedpreferences共享数据,需要使用sharedpreferences API读取数据。使用ContentProvider对外共享数据的好处是统一了数据的访问方式。

 

package com.test;

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.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;

public class MyProvider extends ContentProvider {
	
	//如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,
	public static final String MIME_DIR_PREFIX = "vnd.android.cursor.dir";
	
	//如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,
	public static final String MIME_ITEM_PREFIX = "vnd.android.cursor.item";
	
	public static final String MIME_ITEM = "vnd.msi.people";
		
	public static final String MIME_TYPE_SINGLE = MIME_ITEM_PREFIX + "/" + MIME_ITEM;
	public static final String MIME_TYPE_MULTIPLE = MIME_DIR_PREFIX + "/" + MIME_ITEM;
	
	/*
	 * 主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它
	 * 和androidmanifest.xml中声明的一样
	 */
	public static final String AUTHORITY = "com.test.provider";
	
	public static final String PATH_SINGLE = "people/#";
	public static final String PATH_MULTIPLE = "people";
	
	/*
	 *    Uri代表了要操作的数据,Uri主要包含了两部分信息:1.需要操作的ContentProvider 
	 *    2.对ContentProvider中的什么数据进行操作,一个Uri由scheme,Authority,path三部分组成
	 *    其中scheme由Android所规定, scheme为:content://
	 *    Authority用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
	 *    和androidmanifest.xml中声明的一样
	 *    path可以用来表示我们要操作的数据,路径的构建应根据如下规定:
	 * 		1.要操作person表中id为10的记录,可以构建这样的路径:/person/10
	 * 		2.要操作person表中id为10的记录的name字段, person/10/name
	 *		3. 要操作person表中的所有记录,可以构建这样的路径:/person
	 *		4.要操作xxx表中的记录,可以构建这样的路径:/xxx
	 * 		5.当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:
	 * 		6.要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
	 *		7.如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:
	 */                
	public static final Uri content_URI = Uri.parse("content://" + AUTHORITY + "/" + PATH_MULTIPLE);
	
	//指定查询结果按升序排列
	public static final String DEFAULT_SORT_ORDER = "name DESC";
 
	public static final int PEOPLE = 1;
	public static final int PEOPLES = 2;
	
	
	private static UriMatcher URI_MATCHER;
	private static HashMap<String, String> PROJECTION_MAP;
	
	public static String DB_NAME = "peopledb";
	public static String DB_TABLE_NAME = "people";
	
	SQLiteDatabase db;
	DBOpenHelper dbOpenHelper;
	
	/*
	 * 内部类DBOpenHelper
	 */
	class DBOpenHelper extends SQLiteOpenHelper {
		private final String DB_CREATE = "CREATE TABLE "
				+ DB_TABLE_NAME
				+ " (_id INTEGER PRIMARY KEY,name TEXT UNIQUE NOT NULL,"
				+ "phone TEXT,age INTEGER);";

		public DBOpenHelper(Context context, String dbName, int version) {
			super(context, dbName, null, version);
		}

		public void onCreate(SQLiteDatabase db) {
			try {
				db.execSQL(DB_CREATE);
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

		public void onOpen(SQLiteDatabase db) {
			super.onOpen(db);
		}

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

	/*
	 * 静态块
	 */
	static {
		URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
		/*
		 * 如果match()方法匹配content://com.test.provider/people/# 路径(其中“#”号是通配符) 
		 * 返回匹配码为1
		 */
		URI_MATCHER.addURI(AUTHORITY, PATH_SINGLE, PEOPLE);
		//如果match()方法匹配content://com.test.provider/people路径,返回匹配码为2
		URI_MATCHER.addURI(AUTHORITY, PATH_MULTIPLE, PEOPLES);

		PROJECTION_MAP = new HashMap<String, String>();
		PROJECTION_MAP.put("ID", "_id");
		PROJECTION_MAP.put("NAME", "name");
		PROJECTION_MAP.put("PHONE", "phone");
		PROJECTION_MAP.put("AGE", "age");
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		int count = 0;
		switch (URI_MATCHER.match(uri)) {
		case PEOPLES:
			count = db.delete(DB_TABLE_NAME, selection, selectionArgs);
			break;
		case PEOPLE:
			String segment = uri.getPathSegments().get(1);
			String where = "";
			if (!TextUtils.isEmpty(selection)) {
				where = " AND (" + selection + ")";
			}
			//删除具体某一条
			count = db.delete(DB_TABLE_NAME, "_id=" + segment + where,
					selectionArgs);
			break;
		default:
			break;
		}
		
		/*
		 * 如果ContentProvider的访问者需要知道ContentProvider中的数据发生变化,
		 * 可以在ContentProvider发生数据变化时调
		 * 用getContentResolver().notifyChange(uri, null)来通知注册在此URI上的访问者
		 * 如果ContentProvider的访问者需要得到数据变化通知,必须使用ContentObserver对
		 * 数 据(数据采用uri描述)进行监听,当监听到数据变化通知时,
		 * 系统就会调用ContentObserver的onChange()方法,具体实现如下:
		 * getContentResolver().registerContentObserver(Uri.parse("content://com.test
		 * .provider/people"), true, new PeopleObserver(new Handler()));
		   public class PeopleObserver extends ContentObserver{
   		   		public PersonObserver(Handler handler) {
      	   	  		super(handler);
   		   		}
   		   		public void onChange(boolean selfChange) {
      				//此处可以进行相应的业务处理
   		   		}
			}		
		 */
		getContext().getContentResolver().notifyChange(uri, null);   
		return count;
	}

	@Override
	public String getType(Uri uri) {
		// TODO Auto-generated method stub
		switch (URI_MATCHER.match(uri)) {
		case PEOPLES:
			return MIME_TYPE_MULTIPLE;
		case PEOPLE:
			return MIME_TYPE_SINGLE;
		default:
			throw new IllegalArgumentException("Unkown URI " + uri);
		}
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		long rowId = 0L;
		if (URI_MATCHER.match(uri) != PEOPLES) {
			throw new IllegalArgumentException("Unkown URI" + uri);
		}
		rowId = db.insert(DB_TABLE_NAME, null, values);
		if (rowId > 0) {
			/*
			 * withAppendedId(content_URI, id)用于为路径加上ID部分
			 * 生成后的Uri为:content://com.test.provider/people/rowId
			 */
			Uri result = ContentUris.withAppendedId(content_URI, rowId);
			
			//通知数据变化
			getContext().getContentResolver().notifyChange(result, null); 
			return result;
		} else
			throw new SQLException("Failed to insert row into " + uri);
	}

	@Override
	public boolean onCreate() {
		dbOpenHelper = new DBOpenHelper(this.getContext(), DB_NAME, 1);
		db = dbOpenHelper.getWritableDatabase();
		return false;
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {

		/*
		 * SQLiteQueryBuilder:SQL查询的辅助类
		 * 这个查询类似于一个标准的SQL查询,但是这个查询是SQLiteQueryBuilder 来发起的,而不是
		 * SQLiteDatabase 直接发起的,所以在参数方面略有不同。
		 * 这个函数为 query(SQLiteDatabase db, String[] projectionIn, String selection,
		 * String[] selectionArgs, String groupBy, String having, String sortOrder,
		 * String limit)下边将各个参数介绍一下。
		 * 第一个参数为要查询的数据库实例。
		 * 第二个参数是一个字符串数组,里边的每一项代表了需要返回的列名。
		 * 第三个参数相当于SQL语句中的where部分。
		 * 第四个参数是一个字符串数组,里边的每一项依次替代在第三个参数中出现的问号(?)。
		 * 第五个参数相当于SQL语句当中的groupby部分。
		 * 第六个参数相当于SQL语句当中的having部分。
		 * 第七个参数描述是怎么进行排序。
		 * 第八个参数相当于SQL当中的limit部分,控制返回的数据的个数。
		 */
		SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
		queryBuilder.setTables(DB_TABLE_NAME);
		queryBuilder.setProjectionMap(PROJECTION_MAP);
		
		switch (URI_MATCHER.match(uri)) {
		case PEOPLES:
			break;
		case PEOPLE:
			queryBuilder.appendWhere("_id=" + uri.getPathSegments().get(1));
			break;
		default:
			throw new IllegalArgumentException("Unkonw URI" + uri);
		}
		String orderBy = null;
		if (TextUtils.isEmpty(sortOrder)) {
			orderBy = DEFAULT_SORT_ORDER;
		} else
			orderBy = sortOrder;
		Cursor c = queryBuilder.query(db, projection, selection, selectionArgs,
				null, null, orderBy);
		c.setNotificationUri(getContext().getContentResolver(), uri); 
		return c;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		int count = 0;
		switch (URI_MATCHER.match(uri)) {
		case PEOPLES:
			count = db.update(DB_TABLE_NAME, values, selection, selectionArgs);
			break;
		case PEOPLE:
			String segment = uri.getPathSegments().get(1);
			String where = "";
			if (!TextUtils.isEmpty(selection)) {
				where = " AND (" + selection + ")";
			}
			count = db.update(DB_TABLE_NAME, values, "_id=" + segment + where,
					selectionArgs);
			break;
		default:
			throw new IllegalArgumentException("Unkonw URI" + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null); 
		return count;
	}
}


 

     

   AndroidManifest.xml

   

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test" 
    android:versionCode="1"
    android:versionName="1.0" >

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name="com.test.Hello"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <provider
            android:name="MyProvider"
            android:authorities="com.test.provider"
            android:syncable="true" >
        </provider>
    </application>

    <uses-sdk android:minSdkVersion="7" />

    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.READ_CONTACTS" >
    </uses-permission>

</manifest>

   

 

    可以通过如下代码:调用MyProvider中的方法:

    

ContentValues values = new ContentValues();
values.put("name", “tester”);
values.put("phone", "10086");
values.put("age", 23);
Uri uri = getContentResolver().insert(MyProvider.content_URI,values);

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics