四大组件之ContentProvider使用

本文详细介绍了如何在Android应用中利用ContentProvider实现A应用访问B应用数据库的功能,包括创建ContentProvider、配置权限、实现增删改查操作及观察数据库变化等步骤。同时,解释了如何在B应用中注册ContentResolver访问A应用的ContentProvider,并讨论了权限声明和ContentObserver的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

场景:B应用程序访问A应用程序的数据库

1、A应用程序自定义一个类,继承ContentProvider,相当于对外提供了一个访问的接口。

(1)A应用程序的Manifest.xml文件中声明,代码如下。

name:provider的全名

authorities:主机名,自由命名

exported:true表示能和其他应用程序能交互

<provider
            android:name="com.example.sqlitedemo.MyContentProvider"
            android:authorities="com.example.sqlitedemo.MyContentProvider"
            android:exported="true"/>

(2)MyContentProvider类

public class MyContentProvider extends ContentProvider {
	//主机名
	private static final String authority = "com.example.sqlitedemo.MyContentProvider";
	private static final int INSERT_CODE = 0;
	private static final int DELETE_CODE = 1;
	private static final int UPDATE_CODE = 2;
	private static final int QUERY_CODE = 3;
	private static final int QUERY_ITEM_CODE = 4;
	private static UriMatcher uriMatcher;
	private MySQLiteHelper mySQLiteHelper;

	static {
		// Uri匹配对象,不匹配则返回-1
		uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		// 路径是 content://com.example.sqlitedemo.MyContentProvider/person/insert
		//匹配成功则返回 INSERT_CODE
		uriMatcher.addURI(authority, "person/insert", INSERT_CODE);
		uriMatcher.addURI(authority, "person/delete", DELETE_CODE);
		uriMatcher.addURI(authority, "person/update", UPDATE_CODE);
		uriMatcher.addURI(authority, "person/query", QUERY_CODE);
		// #是数字通配符
		// 路径是 content://com.example.sqlitedemo.MyContentProvider/person/query/10
		uriMatcher.addURI(authority, "person/query/#", QUERY_ITEM_CODE);
	}

	@Override
	public boolean onCreate() {
		mySQLiteHelper = new MySQLiteHelper(getContext(), "test.db", null, 1);
		return false;
	}

	//删除操作时,会调用该方法
	@Override
	public int delete(Uri arg0, String arg1, String[] arg2) {
		if (uriMatcher.match(arg0) == DELETE_CODE) {
			SQLiteDatabase db = mySQLiteHelper.getWritableDatabase();
			if (db.isOpen()) {
				int position = db.delete("person", arg1, arg2);
				db.close();
				return position;
			}
		}
		return 0;
	}

	//增加操作时,会调用该方法
	@Override
	public Uri insert(Uri arg0, ContentValues arg1) {
		if (uriMatcher.match(arg0) == INSERT_CODE) {
			SQLiteDatabase db = mySQLiteHelper.getWritableDatabase();
			if (db.isOpen()) {
				db.insert("person", null, arg1);
				db.close();
			}
		}
		return null;
	}

	//查询操作时,会调用该方法
	@Override
	public Cursor query(Uri uri, String[] arg1, String arg2, String[] arg3,
			String arg4) {
		SQLiteDatabase db = mySQLiteHelper.getReadableDatabase();
		if (uriMatcher.match(uri) == QUERY_CODE) {
			// 查询全部
			if (db.isOpen()) {
				Cursor cursor = db.query("person", arg1, arg2, arg3, null,
						null, arg4);
				return cursor;
				// 不可以关闭数据库
			}
		} else if (uriMatcher.match(uri) == QUERY_ITEM_CODE) {
			// 查询单条数据
			if (db.isOpen()) {
				// 得到Uri尾部追加的ID
				long parseId = ContentUris.parseId(uri);
				Cursor cursor = db.query("person", arg1, "_id = ?",
						new String[] { parseId + "" }, null, null, arg4);
				return cursor;
			}
		}
		return null;
	}

	//更新操作时,会调用该方法
	@Override
	public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
		if (uriMatcher.match(arg0) == UPDATE_CODE) {
			SQLiteDatabase db = mySQLiteHelper.getWritableDatabase();
			if (db.isOpen()) {
				int position = db.update("person", arg1, arg2, arg3);
				db.close();
				return position;
			}
		}
		return 0;
	}

	//获得传进来的URI类型
	@Override
	public String getType(Uri arg0) {
		// TODO Auto-generated method stub
		return null;
	}
}

2、B应用程序获得ContentResolver,然后进行访问。

<span style="white-space:pre">	</span>@Override
	public void onClick(View arg0) {
		// 获得ContentResolver对象,由该对象访问ContentProvider
		ContentResolver contentResolver = getContentResolver();
		switch (arg0.getId()) {
		case R.id.insert:
			//增加操作
			ContentValues contentValues = new ContentValues();
			contentValues.put("name", "duncan");
			contentValues.put("age", 30);
			//把字符串解析为Uri对象,该字符串就是我们ContentProvider对外提供的访问路径
			Uri uriInsert = Uri
					.parse("content://com.example.sqlitedemo.MyContentProvider/person/insert");
			contentResolver.insert(uriInsert, contentValues);
			break;
		case R.id.delete:
			//删除操作
			Uri uriDelete = Uri
					.parse("content://com.example.sqlitedemo.MyContentProvider/person/delete");
			contentResolver.delete(uriDelete, "_id = ?",
					new String[] { String.valueOf(1) });
			break;
		case R.id.update:
			//更新操作
			Uri uriUpdate = Uri
					.parse("content://com.example.sqlitedemo.MyContentProvider/person/update");
			ContentValues cv = new ContentValues();
			cv.put("name", "helloworld");
			contentResolver.update(uriUpdate, cv, "_id = ?",
					new String[] { String.valueOf(2) });
			break;
		case R.id.query:
			//查询全部操作
			Uri uriQuery = Uri
					.parse("content://com.example.sqlitedemo.MyContentProvider/person/query");
			Cursor cursor = contentResolver.query(uriQuery, new String[] {
					"name", "age" }, null, null, null);
			if (cursor != null && cursor.getCount() > 0) {
				while (cursor.moveToNext()) {
					String name = cursor.getString(0);
					int age = cursor.getInt(1);
					Log.i("TAG", "name:" + name + "...age:" + age);
				}
				//关闭Cursor对象
				cursor.close();
			}
			break;
		case R.id.queryItem:
			//查询单条数据操作
			Uri uriItem = Uri
					.parse("content://com.example.sqlitedemo.MyContentProvider/person/query/#");
			//ContentUris类的withAppendedId方法能把该Uri后面的#号替换成3
			//实际路径为 content://com.example.sqlitedemo.MyContentProvider/person/query/3
			Uri newUri = ContentUris.withAppendedId(uriItem, 3);
			Cursor cursorItem = contentResolver.query(newUri, new String[] {
					"name", "age" }, null, null, null);
			if (cursorItem != null && cursorItem.moveToFirst()) {
				String name = cursorItem.getString(0);
				int age = cursorItem.getInt(1);
				Log.i("TAG", "name:" + name + "...age:" + age);
				cursorItem.close();
			}
			break;
		default:
			break;
		}
	}

3、权限问题

A应用程序的Provider访问权限设置为

<provider
            android:name="com.example.sqlitedemo.MyContentProvider"
            android:authorities="com.example.sqlitedemo.MyContentProvider"
            android:readPermission="aa.read"
            android:writePermission="aa.write" 
            android:exported="true"/>
由于aa.read和aa.write是自定义的,所以必须要进行声明。即在本Manifest.xml文件中,加上:

<permission android:name="aa.read" />
<permission android:name="aa.write" />


B应用程序想访问A的Provider,就必须带上这样的权限:

<uses-permission android:name="aa.read"/>
<uses-permission android:name="aa.write"/>


4、观察者ContentObserver

该类主要是用来监听数据库的变化,比如往该数据库上增加一条数据之类的,都能监听到。

(1)B应用程序注册一个监听器

/**
		 *  注册一个内容观察者
		 *  Uri:要监听观察的Uri 
		 *  notifyForDescendents:该Uri的子Uri是否也要观察监听
		 * 	ContentObserver抽象类对象
		 */
		getContentResolver()
				.registerContentObserver(
			Uri.parse("content://com.example.sqlitedemo.MyContentProvider"),
				true, new ContentObserver(new Handler()) {
						@Override
						public void onChange(boolean selfChange) {
							// TODO Auto-generated method stub
							super.onChange(selfChange);
							Log.i(TAG, "数据发生变化了...");
						}

					});

(2)A应用程序发出通知。

// 增加操作时,会调用该方法
	@Override
	public Uri insert(Uri arg0, ContentValues arg1) {
		if (uriMatcher.match(arg0) == INSERT_CODE) {
			SQLiteDatabase db = mySQLiteHelper.getWritableDatabase();
			if (db.isOpen()) {
				db.insert("person", null, arg1);
				//通知观察者,数据变化了
				getContext()
						.getContentResolver()
						.notifyChange(
								Uri.parse("content://com.example.sqlitedemo.MyContentProvider"),
								null);

				db.close();
			}
		}
		return null;
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值