Android数据存储-ContentProvider总结

使用ContentProvider存储数据


1   简介

ContentProvider是android数据存储实现方式之一,它向应用程序之间的数据共享提供了一种机制,它会把数据以表格数据组织的方式对外提供。它具有以下特性:

1)、ContentProvider为存储和获取数据提供了统一的接口。ContentProvide对数据进行封装,不用关心数据存储的细节。使用表的形式来组织数据。

2)、使用ContentProvider可以在不同的应用程序之间共享数据。 

3)、Android为常见的一些数据提供了默认的ContentProvider(包括音频、视频、图片和通讯录等)。 

 

2   Uri

Uri是系统为资源提供的标识,android为每个ContentProvider提供了一个公共的URI,通过这个URI来与ContentProvider提供的数据进行交互。

一个URI的例子如下

content://com.example.test2/member/1

这个URI包括4个部分:

1.      content://ContentProviderscheme,表示由ContentProvider控制数据,由android系统规定。

2.      com.example.test2:ContentProviderauthority,用于唯一标识ContentProvider,外部应用通过此标识与对应的ContentProvider数据进行交互,为了保证它的唯一性,通常我们把它写成和应用程序一样的包名。

3.      memberContentProviderPath,表示我们要操作的具体数据,通常是一张表的名字。

4.      1:这个也是ContentProviderPath,标识我们要操作具体的Item,通常表示一张表的哪条数据。如果Uri没有包含这个标识,则表示要操作全部数据。

 

3   Uri解析

通常我们解析Uri使用android系统提供的操作Uri工具类:UriMatcher。UriMatcher类用来匹配Uri,对匹配结果返回对应的匹配码。

UriMatcher有个addURI方法,用于注册需要匹配的Uri。

它的原型是:

public voidaddURI(String authority, String path, int code)

注册完成之后可以使用UriMatcher类的match()方法匹配Uri,如果匹配成功就返回相应的匹配码,匹配码是使用addURI()注册Uri时传入的第3个参数,注册时传入的匹配码需要唯一。

操作Uri的工具类还有一个ContentUris类,用于操作Uri路径后面的Id,没有深入研究过。。

4   ContentProvider的getType()方法

ContentProvider里面有一个getType()方法,它通过传入的Uri返回一个字符串,具体说明可以参看getType()的注释:

     * Implement this to handle requests forthe MIME type of the data at the
     * given URI.  The returned MIME type should start with
     * <code>vnd.android.cursor.item</code>for a single record,
     * or <code>vnd.android.cursor.dir/</code>for multiple items.

         大概意思是他能够根据给定的Uri返回MIME type类型的数据,当单条记录时,必须以vnd.android.cursor.item开始,当是多条记录是必须以

vnd.android.cursor.dir/开始。

         我的理解是:MIME类型本质是字符串,只不过是增加了特别的限制,例如我们要操作单条记录时,必须以vnd.android.cursor.item开始,当我们要操作多条记录时,必须以

vnd.android.cursor.dir/开始,后面可以增加自己定义的字符串,这样做系统可以通过前面部分就知道我们所要做的操作。

 

5   ContentProvider主要方法

public boolean onCreate():

ContentProvider创建时调用

public String getType(Uri uri):

返回给定Uri对应的MIME类型字符串

public Uri insert(Uri uri, ContentValuesvalues)

供外部应用往ContentProvider插入数据

public int update(Uri uri, ContentValuesvalues, String selection,String[] selectionArgs):

供外部应用更新ContentProvider数据

public int delete(Uri uri, Stringselection, String[] selectionArgs):

供外部应用删除ContentProvider数据

public Cursor query(Uri uri, String[]projection, String selection,String[] selectionArgs, String sortOrder):

供外部应用查询ContentProvider数据

 

6   ContentProvider操作

外部应用可以通过ContentResolver类来完成对ContentProvider的数据操作,这些数据操作包括insert,delete,update,update,分别对应上述ContentProvider提供的4个数据操作方法。

public final Uri insert(Uri url,ContentValues values):

往ContentProvider插入数据

public final int update(Uri uri,ContentValues values, String where,String[] selectionArgs):

更新ContentProvider数据

public final int delete(Uri url, Stringwhere, String[] selectionArgs):

删除ContentProvider数据

public final Cursor query(Uri uri,String[] projection,String selection, String[] selectionArgs, String sortOrder)

查询ContentProvider数据

public final Cursor query(final Uriuri, String[] projection,String selection, String[] selectionArgs, StringsortOrder,CancellationSignal cancellationSignal)

查询ContentProvider数据,最后一个参数代表取消信号监听器

 

7   ContentProvider使用方法

1.       定义CONTENT_URI常量,用来表示ContentProvider的访问标识符。

2.      定义ContentProvider的子类。

3.      定义UriMatcher实例,添加需要匹配的Uri

4.      实现getType()方法,返回对应UriMIME字符串。

5.      实现增删改查的方法

6.      AndroidManifest.xml对自定义的ContentProvider进行注册。

7.      使用ContentResolver实例进行增删改查操作


8   测试代码

常量类:

public interface Database { 
	
	public static final String AUTHORITY = "com.example.test2";

	// 表示member表的元数据定义,直接继承_ID和_COUNT静态常量
	public static interface MemberTableMetaData extends BaseColumns {
		// 数据表的名称
		public static final String TABLE_NAME = "member";

		public static final Uri CONTENT_URI = Uri.parse("content://"
				+ AUTHORITY + "/" + TABLE_NAME);
		// 取得member表中的所有数据
		public static final String CONTACT_LIST = "vnd.android.cursor.dir/member";
		// 取得一个member信息,相当于是按照ID查询
		public static final String CONTACT_ITEM = "vnd.android.cursor.item/member";
		// 表示member.name字段名称
		public static final String MEMBER_NAME = "name";
		// 表示member.age字段名称
		public static final String MEMBER_AGE = "age";
		// 表示member.birthday字段名称
		public static final String MEMBER_BIRTHDAY = "birthday";
		// 显示时的排序字段
		public static final String SORT_ORDER = "_id DESC";
	}
}

SQLite类

public class Helper extends SQLiteOpenHelper { // 继承SQLiteOpenHelper类
	
	private static final String DATABASENAME = "contentprovider.db" ; // 数据库名称
	private static final int DATABASEVERSION = 5 ; // 数据库名称
	private static final String TABLENAME = "member" ; // 数据表名称
	public Helper(Context context) {
		super(context, DATABASENAME, null, DATABASEVERSION); // 调用父类构造
	}
	@Override
	public void onCreate(SQLiteDatabase db) { // 创建数据表
		String sql = "CREATE TABLE " + TABLENAME + " ("
				+ Database.MemberTableMetaData._ID
				+ "			INTEGER 		PRIMARY KEY ,"
				+ Database.MemberTableMetaData.MEMBER_NAME
				+ "	VARCHAR(50)		NOT NULL ,"
				+ Database.MemberTableMetaData.MEMBER_AGE
				+ "		INTEGER			NOT NULL ,"
				+ Database.MemberTableMetaData.MEMBER_BIRTHDAY
				+ "	DATE			NOT NULL)"; // SQL语句
		db.execSQL(sql) ; // 执行SQL语句
	}
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		String sql = "DROP TABLE IF EXISTS " + TABLENAME ; // SQL语句
		db.execSQL(sql); // 执行SQL语句
		this.onCreate(db); // 创建表
	}
}

ContentProvider

public class Member extends ContentProvider {	// 继承ContentProvider
	
	private static UriMatcher uriMatcher = null; // 定义UriMatcher对象
	private static final int GET_MEMBER_LIST = 1; // 查询全部的常量标记
	private static final int GET_MEMBER_ITEM = 2; // 根据ID查询的常量标记
	private Helper helper = null; // 数据库操作类对象
	
	static { // 静态代码块
		uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); // 实例化UriMatcher
		uriMatcher.addURI(Database.AUTHORITY, "member",
				GET_MEMBER_LIST); // 增加匹配地址
		uriMatcher.addURI(Database.AUTHORITY, "member/#",
				GET_MEMBER_ITEM); // 增加匹配地址
	}
	
	@Override
	public boolean onCreate() {
		System.out.println("------------> onCreate");
		this.helper = new Helper(super.getContext()); // 实例化DatabaseHelper
		return false; // 操作成功
	}
	
	@Override
	public String getType(Uri uri) { // 得到MIME
		System.out.println("------------> getType");
		switch (uriMatcher.match(uri)) { // 匹配传入的URI
		case GET_MEMBER_LIST: // 满足条件
			return Database.MemberTableMetaData.
				CONTACT_LIST; // 返回所有member信息
		case GET_MEMBER_ITEM: { // 满足条件
			return Database.MemberTableMetaData.
				CONTACT_ITEM; // 返回一个member信息
		}
		default: // 不匹配时返回默认
			throw new UnsupportedOperationException("Not Support Operation:" + uri); // 抛出异常
		}
	}
	
	@Override
	public Uri insert(Uri uri, ContentValues values) { // 数据增加
		System.out.println("------------> insert");
		SQLiteDatabase db = this.helper.getWritableDatabase(); // 取得数据库操作对象
		long id = 0; // 增加之后的id
		switch (uriMatcher.match(uri)) { // 匹配传入的UR
		case GET_MEMBER_LIST: // 满足条件
			id = db.insert(Database.MemberTableMetaData.TABLE_NAME,
					Database.MemberTableMetaData._ID, 
					values); // 执行插入
			return ContentUris.withAppendedId(uri, id); // 返回Uri后面追加ID
		case GET_MEMBER_ITEM: // 满足条件
			id = db.insert(Database.MemberTableMetaData.TABLE_NAME,
					Database.MemberTableMetaData._ID, 
					values); // 执行插入
			String uriPath = uri.toString(); // 取出地址
			String path = uriPath.substring(0, 
					uriPath.lastIndexOf("/")) + id; // 建立新的Uri地址
			return Uri.parse(path); // 返回一个member信息
		default: // 不匹配时返回默认
			throw new UnsupportedOperationException("Not Support Operation:" + uri); // 抛出异常
		}
	}
	
	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) { // 更新操作
		System.out.println("------------> update");
		SQLiteDatabase db = this.helper.getWritableDatabase(); // 取得数据库操作对象
		int result = 0; // 操作结果
		switch (uriMatcher.match(uri)) { // 匹配传入的URI
		case GET_MEMBER_LIST: // 满足条件
			result = db.update(
					Database.MemberTableMetaData.TABLE_NAME,
					values, null, null); // 更新记录
			break;
		case GET_MEMBER_ITEM: // 满足条件
			long id = ContentUris.parseId(uri); // 取出传过来的id
			String where = "_id=" + id; // 更新条件
			result = db.update(
					Database.MemberTableMetaData.TABLE_NAME,
					values, where, selectionArgs); // 执行更新操作
			break;
		default: // 不匹配时返回默认
			throw new UnsupportedOperationException("Not Support Operation:"
					+ uri); // 抛出异常
		}
		return result; // 返回更新的行数
	}
	
	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		System.out.println("------------> delete");
		SQLiteDatabase db = this.helper.getWritableDatabase(); // 取得数据库操作对象
		int result = 0; // 操作结果
		switch (uriMatcher.match(uri)) { // 匹配传入的UR
		case GET_MEMBER_LIST: // 满足条件
			result = db.delete(
					Database.MemberTableMetaData.TABLE_NAME,
					selection, selectionArgs); // 删除数据
			break;
		case GET_MEMBER_ITEM: // 满足条件
			long id = ContentUris.parseId(uri); // 取得传入的id
			String where = "_id=" + id; // 删除语句
			result = db.delete(
					Database.MemberTableMetaData.TABLE_NAME, where,
					selectionArgs); // 删除数据
			break;
		default: // 不匹配时返回默认
			throw new UnsupportedOperationException("Not Support Operation:"
					+ uri); // 抛出异常
		}
		return result; // 删除的行数
	}
	
	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) { // 查询操作
		System.out.println("------------> query");
		SQLiteDatabase db = this.helper.getWritableDatabase(); // 取得数据库操作对象
		switch (uriMatcher.match(uri)) { // 匹配传入的UR
		case GET_MEMBER_LIST: // 满足条件
			return db
					.query(Database.MemberTableMetaData.TABLE_NAME,
							projection, selection, selectionArgs, null, null,
							sortOrder); // 查询
		case GET_MEMBER_ITEM: // 满足条件
			long id = ContentUris.parseId(uri); // 取出传入ID
			String where = "_id=" + id; // 查询条件
			return db.query(
					Database.MemberTableMetaData.TABLE_NAME,
					projection, where, selectionArgs, null, null, 
					sortOrder); // 查询操作
		default: // 不匹配时返回默认
			throw new UnsupportedOperationException("Not Support Operation:"
					+ uri); // 抛出异常
		}
	} 
}

Activity:

public class Contentprovider extends Activity {
	
	private Button insertBut,updateBut,deleteBut,queryBut ;	// 定义按钮组件
	private ListView membersList ; // 定义ListView
	private TextView mainInfo = null; // 操作提示

	public long testInsert(String name, int age, String birthday)
			throws Exception { // 测试增加操作
		ContentResolver contentResolver = null ; // 定义ContentResolver
		contentResolver = super.getContentResolver(); // 取得ContentResolver
		ContentValues values = new ContentValues(); // 设置内容
		values.put(Database.MemberTableMetaData.MEMBER_NAME, name); // 设置name字段内容
		values.put(Database.MemberTableMetaData.MEMBER_AGE, age); // 设置age字段内容
		values.put(Database.MemberTableMetaData.MEMBER_BIRTHDAY, birthday); // 设置birthday字段内容
		Uri resultUri = contentResolver.insert(Database.MemberTableMetaData.CONTENT_URI, values); // 执行增加操作
		return ContentUris.parseId(resultUri) ; // 解析ID返回
	}
	
	public long testUpdate(String _id, String name, int age, String birthday)
			throws Exception { // 测试修改操作
		long result = 0 ; // 保存返回结果
		ContentResolver contentResolver = null ; // 定义ContentResolver
		contentResolver = super.getContentResolver(); // 取得ContentResolver
		ContentValues values = new ContentValues(); // 设置内容
		values.put(Database.MemberTableMetaData.MEMBER_NAME, name); // 设置name字段内容
		values.put(Database.MemberTableMetaData.MEMBER_AGE, age); // 设置age字段内容
		values.put(Database.MemberTableMetaData.MEMBER_BIRTHDAY, birthday); // 设置birthday字段内容
		if(_id == null || "".equals(_id)) { // 根据id更新
			result = contentResolver.update(Database.MemberTableMetaData.CONTENT_URI, values, null, null); 						// 更新操作
		} else { // 更新全部
			result = contentResolver.update(Uri.withAppendedPath(Database.MemberTableMetaData.CONTENT_URI, _id),values, null, null); 						// 更新操作
		}
		return result; // 返回更新结果
	}
	
	public long testDelete(String _id) throws Exception { // 测试删除操作
		ContentResolver contentResolver = null ; // 定义ContentResolver
		contentResolver = super.getContentResolver(); // 取得ContentResolver
		long result = 0 ; // 更新记录数
		if (_id == null || "".equals(_id)) { // 删除全部数据
			result = contentResolver.delete(Database.MemberTableMetaData.CONTENT_URI, null, null); // 执行删除操作
		} else {
			result = contentResolver.delete(Uri.withAppendedPath(Database.MemberTableMetaData.CONTENT_URI, _id),null, null); 								// 执行删除操作
		}
		return result; // 返回更新记录数
	}
	
	public Cursor testQuery(String id) throws Exception { // 测试增加操作
		if(id==null || "".equals(id)){ // 查询全部
			return super.getContentResolver().query(
					Database.
					MemberTableMetaData.CONTENT_URI, null, null, null,
					Database.
					MemberTableMetaData.SORT_ORDER); // 执行查询操作
		} else { // 根据id查询
			return super
					.getContentResolver()
					.query(Uri.withAppendedPath(
							Database.MemberTableMetaData.CONTENT_URI,
							id), null, null, null,
							Database.
							MemberTableMetaData.SORT_ORDER); // 执行查询操作
		}
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		super.setContentView(R.layout.a130912_activity_contentprovider_1);					// 指定布局管理器
		// 依次取得Button、TextView、ListView组件的实例
		this.membersList = (ListView) super.findViewById(R.id.membersList);
		this.insertBut = (Button) super.findViewById(R.id.insertBut) ;
		this.updateBut = (Button) super.findViewById(R.id.updateBut) ;
		this.deleteBut = (Button) super.findViewById(R.id.deleteBut) ;
		this.queryBut = (Button) super.findViewById(R.id.queryBut) ;
		this.mainInfo = (TextView) super.findViewById(R.id.mainInfo) ;
		this.insertBut.setOnClickListener(new InsertOnClickListener()) ;// 单击事件操作
		this.updateBut.setOnClickListener(new UpdateOnClickListener()) ;// 单击事件操作
		this.deleteBut.setOnClickListener(new DeleteOnClickListener()) ;// 单击事件操作
		this.queryBut.setOnClickListener(new QueryOnClickListener()) ;	// 单击事件操作
	}
	
	private class InsertOnClickListener implements OnClickListener {// 增加按钮的单击事件
		@Override
		public void onClick(View view) {
			Contentprovider.this.mainInfo.
				setText("执行的是增加操作..."); 				// 设置显示文字
			long id = 0 ;									// 保存接收ID
			try {
				id = Contentprovider.this.testInsert("李晓峰",30,
					new SimpleDateFormat("yyyy-MM-dd").
					format(new Date())) ;					// 增加数据
			} catch (Exception e) {
				e.printStackTrace();
			}
			Toast.makeText(Contentprovider.this, "数据增加成功,ID为:" + id,
					Toast.LENGTH_LONG).show();				// 信息提示
		}
	}
	
	private class UpdateOnClickListener implements OnClickListener {
		@Override
		public void onClick(View view) {
			Contentprovider.this.mainInfo.
				setText("执行的是修改操作...");				// 显示文字
			long result = 0 ;								// 更新记录
			try {
				result = Contentprovider.this.testUpdate("13", "李小明", 18,
						"1989-09-19");						// 更新数据
			} catch (Exception e) {
				e.printStackTrace();
			}
			Toast.makeText(Contentprovider.this, "更新了" + result + "条记录!",
					Toast.LENGTH_LONG).show();				// 信息提示
		}
	}
	
	private class DeleteOnClickListener implements OnClickListener {
		@Override
		public void onClick(View view) {
			Contentprovider.this.mainInfo.
				setText("执行的是删除操作...");				// 显示文字
			long result = 0 ;								// 更新记录
			try {
				result = Contentprovider.
					this.testDelete("4") ;					// 删除数据
			} catch (Exception e) {
				e.printStackTrace();
			}
			Toast.makeText(Contentprovider.this, "删除了" + result + "条记录!",
					Toast.LENGTH_LONG).show();				// 信息提示
		}
	}
	
	private class QueryOnClickListener implements OnClickListener {
		@Override
		public void onClick(View arg0) {
			Contentprovider.this.mainInfo.
				setText("执行的是查询操作...");				// 显示文字
			Cursor result = null ;							// 结果集
			try {
				result = Contentprovider.
					this.testQuery(null);					// 查询全部数据
			} catch (Exception e) {
				e.printStackTrace();
			}
			Log.v("test", "result = " + (result == null));
			Contentprovider.this.
				startManagingCursor(result) ;				// Cursor交由系统管理
			List<Map<String, Object>> members = null ;		// 用于设置SimpleAdapter
			members = new ArrayList<Map<String, Object>>();// 实例化List集合
			for (result.moveToFirst(); !result.isAfterLast(); result
					.moveToNext()) {						// 循环取数据
				Map<String, Object> member = new HashMap<String, Object>();
				member.put("_id", result.getInt(0)) ;		// 设置一行的_id内容
				member.put("name", result.getString(1)) ;	// 设置一行的name内容
				member.put("age",result.getInt(2)) ;		// 设置一行的age内容
				member.put("birthday", result.getString(3));// 设置一行的birthday内容
				members.add(member) ;						// 保存Map
			}
			Contentprovider.this.membersList
					.setAdapter(new SimpleAdapter(
							Contentprovider.this, 	// 将数据包装
							members, 						// 数据集合
							R.layout.a130912_activity_contentprovider_1_member, 				// 显示的布局管理器
							new String[] { "_id", "name", 
									"age", "birthday" }, 	// 匹配的Map集合的KEY
							new int[] { R.id._id, R.id.name, R.id.age,
									R.id.birthday }));		// 显示数据
			Toast.makeText(Contentprovider.this, "数据查询成功!",
					Toast.LENGTH_LONG).show();				// 信息提示
		}
	}
}

AndroidManifest.xml

<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        
		<activity android:name="com.example.test2.contentProvider.Contentprovider"/>
	   	<provider android:name="com.example.test2.contentProvider.Member"
			android:authorities="com.example.test2"
			android:exported="true"
			/>			
    </application>








 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值