ContentProvider & ContentResolver & ContentObserver

1.四大组件之一
  作用:暴露应用的数据。可以获取不同应用的数据。

  /data/data/应用包/databases/xxx.db

2.创建一个类继承Provider
  Provider自身方法: onCreate query insert delete update getType  --- 必须要重写

  Provider要访问本应用数据库,需要在Provider中创建一个SQLiteOpenHelper,并且在onCreate方法中实例化。
  然后再每个要执行数据库操作方法中(query insert delete update)通过helper打开数据库并使用数据库相应方法。

  Cursor query(...)  查询返回值为Cursor,即查询内容都在Cursor中
  Uri insert(...)  返回新添加数据的uri
  int update(...)  返回更新操作影响的行数
  int delete(...)  返回删除操作影响的行数

  其原理就是在Provider中保存一个SQLiteOpneHelper,通过helper得到SQLiteDatabase。
  然后在其增删改查的方法中,调用database的相应的增删改查方法。


3.在清单中注册
  四大组件之一,要注册。
  注册时,需要类名与权限(android:authorities),权限即为对外暴露的访问该提供者的标示
 
  当应用程序启动,会自动创建内容提供者。


4.访问内容提供者,使用ContentResolver
  ContentResolver resolver = getContentResolver();

  Resolver方法:query insert delete update


5.Uri
  1)Uri格式:content://主机名或authority/路径(路径中可包含ID)
    content://com.itheima/person/1

    Uri.parse("uri...")

    注意:操作ID要使用类ContentUris,见后。

  2)安卓自身的Uri以及表字段,都有对应的常量。

    联系人Uri常量:Calls.CONTENT_URI;
    联系人通话记录表中字段Calls.NUMBER --- 电话号码,Calls.DURATION --- 通话时长, Calls._ID --- ID号。

    多媒体Uri常量:(andrdroid.provider.MediaStore.Audio.)Media.EXTERNAL_CONTENT_URI --- 访问音频外部存储的Uri

                                (andrdroid.provider.MediaStore.Audio.)Media.INTERNAL_CONTENT_URI --- 访问音频手机内存的Uri


  (android.provider.MediaStore.Images.)Media.EXTERNAL_CONTENT_URI / Media.INTERNAL_CONTENT_URI 图像

  (android.provider.MediaStore.Video.)Media.EXTERNAL_CONTENT_URI / Media.INTERNAL_CONTENT_URI  视频

  多媒体表字段: Media._ID;  ID号        Media.DISPLAY_NAME 名称     Media.SIZE 大小


6.在内容提供者里面定义一组Uri
  UriMatcher
  方法:addURI(authority, path, code);
  如:
  matcher.addURI(authority, path, code);


  参数:
       authority即为清单中provider的authority
       code为匹配码,即该uri对应的唯一码,matcher.match(uri)的返回值

  matcher.addURI(authority, "m", 1000);
  matcher.addURI(authority, "m/#", 1000);
  注:#代表数字, *代表字符
   

  代码:

class MyProvider extends ContentProvider{

	//authority即为清单中注册的authority
	private static final String authority = "...";
	private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); 
  	static{   
		matcher.addURI(authority, "...", code);
        }
  }

match方法


7.ContentUris
  该类用于获取Uri路径后面的ID部分,也可以为Uri路径加上ID部分。

  添加ID -- withAppendId()
  Uri uri = Uri.parse("content://....");
  Uri resultUri = ContentUris.withAppendId(uri, 10);

  获取ID -- parseId()
  Uri uri = Uri.parse("content://..../10");

  long personId = ContentUris.parseId(uri);


示例:一个应用访问另一个应用的数据库。

Provider应用

public class MyProvider extends ContentProvider {

	private MyOpenHelper helper;

	private static final int MM = 10;
	private static final int MM_ID = 100;

	// 表名
	private String table = "mm";

	private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
	// 与清单provider的authority一致
	private static String authority = "yp";
	static {
		// content://yp/mm
		matcher.addURI(authority, "mm", MM);
		// content://yp/mm/1
		matcher.addURI(authority, "mm/#", MM_ID);
	}

	@Override
	public boolean onCreate() {
		helper = MyOpenHelper.getInstance(getContext());
		return false;
	}

	/**
	 * 查询
	 */
	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		SQLiteDatabase db = helper.getReadableDatabase();

		// 获得uri匹配码
		int code = matcher.match(uri);
		Cursor cursor = null;

		// 通过判断匹配码,根据不同的uri做不同的操作
		switch (code) {
		// uri中没有带指定的id
		case MM:
			// select * form mm where name = xxx
			cursor = db.query(table, new String[] { "*" }, selection,
					selectionArgs, null, null, null);
			break;

		// uri中带有指定的id
		case MM_ID:
			// 获取指定的id
			long id = ContentUris.parseId(uri);
			// 判断对方是否包含查询条件
			if (selection == null) {
				// 如果不包含查询条件
				selection = "_id = ?";
				selectionArgs = new String[] { id + "" };
			} else {
				// 如果包含查询条件,将id条件拼接
				// select * from mm where name = xxx and id = xx
				selection = selection + " and _id = " + id;
			}
			cursor = db.query(table, new String[] { "*" }, selection,
					selectionArgs, null, null, null);
			break;

		default:
			break;
		}

		// 数据库不可以关闭
		return cursor;
	}

	/**
	 * 插入
	 */
	@Override
	public Uri insert(Uri uri, ContentValues values) {

		SQLiteDatabase db = helper.getWritableDatabase();
		long id = db.insert(table, "_id", values);
		return ContentUris.withAppendedId(uri, id);
	}

	/**
	 * 更新
	 */
	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		SQLiteDatabase db = helper.getReadableDatabase();
		// 获得uri匹配码
		int code = matcher.match(uri);

		int rows = 0;

		// 通过判断匹配码,根据不同的uri做不同的操作
		switch (code) {
		// uri中没有带指定的id
		case MM:
			rows = db.update(table, values, selection, selectionArgs);
			break;

		// uri中带有指定的id
		case MM_ID:
			// 获取指定的id
			long id = ContentUris.parseId(uri);
			// 判断对方是否包含查询条件
			if (selection == null) {
				// 如果不包含查询条件
				selection = "_id = ?";
				selectionArgs = new String[] { id + "" };
			} else {
				// 如果包含查询条件,将id条件拼接
				selection = selection + " and _id = " + id;
			}
			rows = db.update(table, values, selection, selectionArgs);
			break;

		default:
			break;
		}

		return rows;
	}

	/**
	 * 删除
	 */
	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		SQLiteDatabase db = helper.getReadableDatabase();

		// 获得uri匹配码
		int code = matcher.match(uri);

		int ret = 0;

		// 通过判断匹配码,根据不同的uri做不同的操作
		switch (code) {
		// uri中没有带指定的id
		case MM:
			db.delete(table, selection, selectionArgs);
			break;

		// uri中带有指定的id
		case MM_ID:
			// 获取指定的id
			long id = ContentUris.parseId(uri);
			// 判断对方是否包含查询条件
			if (selection == null) {
				// 如果不包含查询条件
				selection = "_id = ?";
				selectionArgs = new String[] { id + "" };
			} else {
				// 如果包含查询条件,将id条件拼接
				selection = selection + " and _id = " + id;
			}
			ret = db.delete(table, selection, selectionArgs);
			break;

		default:
			break;
		}

		return ret;
	}

	@Override
	public String getType(Uri uri) {
		return null;
	}

}

Resolver应用

public class MainActivity extends Activity {

	private ContentResolver resolver;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		resolver = getContentResolver();
	}

	public void click(View v) {
		ContentValues values = new ContentValues();

		switch (v.getId()) {
		case R.id.insert:
			values.clear();
			values.put("name", "ly");
			values.put("age", 20);
			resolver.insert(Uri.parse("content://yp/mm"), values);
			break;

		case R.id.update:
			values.clear();
			values.put("name", "yl");
			values.put("age", 18);
			resolver.update(Uri.parse("content://yp/mm/10"), values, null, null);
			break;

		case R.id.delete:
			resolver.delete(Uri.parse("content://yp/mm"), "name = ?",
					new String[] { "yl" });
			break;

		case R.id.query:
			Cursor cursor = resolver.query(Uri.parse("content://yp/mm"),
					new String[] { "*" }, null, null, null);
			while (cursor.moveToNext()) {
				int _id = cursor.getInt(0);
				String name = cursor.getString(1);
				int age = cursor.getInt(2);
				System.out.println("_id = " + _id + " name = " + name
						+ " age = " + age);
			}
			cursor.close();
			break;

		default:
			break;
		}
	}
}

8.UriMatcher与ContentUris
  UriMatcher.match()方法与ContentUris.withAppendId/parseId方法区别。
  
  一条uri:  "content://ly/mm/10"   
  使用UriMatcher.addURI()方法:matcher.addURI(authority, "mm", 100);    是将这条URI独一无二的分配100标识码。即后面使用matcher.match(uri);的返回值如果是100,那么当前uri就是 "content://ly/mm/10"。

  而ContentUris操作的是uri最后的 '10'  ,即向uri最后插入数字或者获取uri最后的数字。


9.ContentObserver

  内容观察者,观察内容提供者数据的变化。

  如果内容提供者数据变化了,那么发送信息给观察者。

  原理:在resolver身上注册一个观察者observer,当数据改变时,调用观察者的onChange方法
        在provider的数据会发生改变的方法中调用resolver的notifyChange方法。


  1) 在Provider中数据改变要通知的某方法内(如insert)
     getContext().getContentProvider().nofityChange(uri, observer);

     例:getContext().getContentProvider().nofityChange(uri, null);

  2) 在数据改变时需要被通知的类中,写一个内部类继承ContentObserver。
     并实现构造方法和onChange(boolean selfChange)方法。数据发生改变时,onChange方法被调用

  3) 在该类中注册观察者
     resolver.registerContentObserver(uri, notifyForDescendents, observer);
     第二个参数为boolean类型的值,表示是否级联。
     如:uri为 content://yp/mm   那么content://yp/mm/10发生变化时是否通知。

     例:resolver.registerContentObserver(uri, false, observer);


    


Provider

/**
	 * 插入
	 */
	@Override
	public Uri insert(Uri uri, ContentValues values) {

		//数据改变时发出通知
		getContext().getContentResolver().notifyChange(uri, null);
		
		SQLiteDatabase db = helper.getWritableDatabase();
		long id = db.insert(table, "_id", values);
		return ContentUris.withAppendedId(uri, id);
	}

LApp

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		ContentResolver resolver = getContentResolver();
		MyObserver observer = new MyObserver(new Handler());
		// 注册观察者
		resolver.registerContentObserver(Uri.parse("content://yp/mm"), false,
				observer);
		System.out.println("内容观察者已经注册");
	}

	private class MyObserver extends ContentObserver {

		public MyObserver(Handler handler) {
			super(handler);
		}

		@Override
		public void onChange(boolean selfChange) {
			super.onChange(selfChange);
			System.out.println("数据已经发生改变!!!");
		}

	}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值