ContentProvider & ContentResolver & ContentObserver

来源:互联网 发布:知世故而不世故谁写的 编辑:程序博客网 时间:2024/05/22 01:09
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即为清单中注册的authorityprivate 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/mmmatcher.addURI(authority, "mm", MM);// content://yp/mm/1matcher.addURI(authority, "mm/#", MM_ID);}@Overridepublic boolean onCreate() {helper = MyOpenHelper.getInstance(getContext());return false;}/** * 查询 */@Overridepublic 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中没有带指定的idcase MM:// select * form mm where name = xxxcursor = db.query(table, new String[] { "*" }, selection,selectionArgs, null, null, null);break;// uri中带有指定的idcase MM_ID:// 获取指定的idlong id = ContentUris.parseId(uri);// 判断对方是否包含查询条件if (selection == null) {// 如果不包含查询条件selection = "_id = ?";selectionArgs = new String[] { id + "" };} else {// 如果包含查询条件,将id条件拼接// select * from mm where name = xxx and id = xxselection = selection + " and _id = " + id;}cursor = db.query(table, new String[] { "*" }, selection,selectionArgs, null, null, null);break;default:break;}// 数据库不可以关闭return cursor;}/** * 插入 */@Overridepublic Uri insert(Uri uri, ContentValues values) {SQLiteDatabase db = helper.getWritableDatabase();long id = db.insert(table, "_id", values);return ContentUris.withAppendedId(uri, id);}/** * 更新 */@Overridepublic 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中没有带指定的idcase MM:rows = db.update(table, values, selection, selectionArgs);break;// uri中带有指定的idcase MM_ID:// 获取指定的idlong 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;}/** * 删除 */@Overridepublic 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中没有带指定的idcase MM:db.delete(table, selection, selectionArgs);break;// uri中带有指定的idcase MM_ID:// 获取指定的idlong 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;}@Overridepublic String getType(Uri uri) {return null;}}

Resolver应用

public class MainActivity extends Activity {private ContentResolver resolver;@Overrideprotected 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

/** * 插入 */@Overridepublic 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 {@Overrideprotected 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);}@Overridepublic void onChange(boolean selfChange) {super.onChange(selfChange);System.out.println("数据已经发生改变!!!");}}}

0 0
原创粉丝点击