ContentProvider是Android四大组件之一,它用来封装数据,并通过ContentResolver接口将数据提供给其他应用。只有当需要在多个应用之间共享数据时才会用到ContentProvider。
多个应用共享数据时,如何区分是哪个应用中的那部分数据呢?
ContentProvider通过Uri标识具体某个应用的某些数据。当一个应用提供了ContentProvider向其他应用共享数据时,该应用在其ContentProvider中添加标识自己特定数据的Uri,然后其他应用想要获得这些数据时,则可以通过向ContentResolver接口的方法传入标识要访问的数据的Uri即可。
如应用B和应用C都向外提供数据,他们就需要在自己提供的ContentProvider中分别指明自己所能解析的Uri。应用A要访问应用B和应用C提供的数据,就需要使用ContentResolver接口,要向该接口的访问数据的方法中传入特定的Uri以区分是要访问应用B的数据,还是要访问应用C的数据。
应用之间共享数据需要用到的类和接口有:ContentProvider、ContentResolver、Uri、UriMatcher、ContentUris等。
下面一一学习这几个类和接口的简单使用:
1)ContentProvider:
该类是一个抽象类,要在自己应用中使用ContentProvider对象,需要自定义类继承ContentProvider类,并实现几个主要的抽象方法:
onCreate()方法: 其它应用第一次访问该ContentProvider时被调。
insert()方法:外部应用使用此方法添加数据。
delete()方法:外部应用使用此方法删除数据。
update ()方法:外部应用使用此方法更新数据。
query()方法:外部应用使用此方法查询数据。
getType()方法: 主要用于匹配数据类型,返回当前Uri所代表数据的MIME类型。如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/自定义类型。数据属于非集合类型数据,应该返回vnd.android.cursor.item/自定义类型。
2)ContentResolver:
是一个接口,可以通过Context.getContentResolver()获取该接口的实例,当在自己应用中要访问别的应用ContentProvider提供的数据时,需要获取该接口的实例,然后调用该接口的insert()、update()、query()、delete()等方法,最终会调用对应ContentProvider中同名的方法,实现共享数据的增删改查操作。
3)Uri:
也是一个抽象类。
Uri标准的格式是:schema://主机名authority/path[/ID]
后面的ID部分根据访问需要,可能没有。
如:content://cn.csc.app1/student标识要访问的是cn.csc.app1所标识的应用中的student表。
ContentProvider中Uri的schema部分一般为content://
authority用来标识要访问的是哪个ContentProvider,通常用能唯一标识应用的包名作为authority。
path部分,则标识我们要访问的是哪些数据,如student表示我们要访问的是student表的数据。
若加上ID部分,如content://cn.csc.app1/student/10,一般被用来表示我们要访问的是student表中的id为10的那条数据。
uri中可以使用通配符:
*:表示匹配任意长度的字符串
#:表示匹配任意长度的数字串
如匹配任意表的uri可以表示为:content://cn.csc.app1/*
匹配student表中任意一条记录的uri:content://cn.csc.app1/student/#
常用到的是Uri中的一个静态方法:
parse()用来将字符串表示的uri解析为Uri对象。
4)UriMatcher:
Uri匹配的一个工具类,一般用在ContentProvider中:
一般使用常量NO_MATCH作为参数,构造UriMatcher对象,然后调用addURI()方法向该对象中添加URI,使用match()方法判断传入的Uri的匹配结果。
addURI()方法的参数说明:
authority:Uri中的authority用于标识是哪个ContentProvider
path:Uri中的path部分,标识要操作的是哪张表
code:用于设置当前添加的Uri的标识码,当使用match方法,传入一个Uri参数时,会将匹配到的Uri对应的code返回,以指明当前匹配到哪个Uri。
5)ContentUris:
一个实用的对Uri进行操作的工具类
parseId():用来获取传入的Uri中的Id部分
withAppendId():用于将传入的Uri和id拼接起来。
下面是实际编写ContentProvider的一个简单示例:
第一步:要先有一个数据库帮助类,以便于进行数据库增删改查操作
1 package cn.csc.content_provider.db; 2 3 4 5 import android.content.Context; 6 7 import android.database.sqlite.SQLiteDatabase; 8 9 import android.database.sqlite.SQLiteOpenHelper; 10 11 import android.database.sqlite.SQLiteDatabase.CursorFactory; 12 13 import android.util.Log; 14 15 16 17 public class MySqliteHelper extends SQLiteOpenHelper { 18 19 public static final String TAG = "MYSQLITEHELPER"; 20 21 public static final String CREATE_STUDENT = "create table t_student (" + 22 23 "id integer primary key, name varchar(20), " + 24 25 "gender varchar(10), age integer)"; 26 27 public static final String CREATE_TEACHER = "create table t_teacher(" + 28 29 "id integer primary key, name varchar(20))"; 30 31 public MySqliteHelper(Context context, String name, CursorFactory factory, 32 33 int version) { 34 35 super(context, name, factory, version); 36 37 } 38 39 40 41 @Override 42 43 public void onOpen(SQLiteDatabase db) { 44 45 Log.i(TAG,"open db"); 46 47 super.onOpen(db); 48 49 } 50 51 52 53 @Override 54 55 public void onCreate(SQLiteDatabase db) { 56 57 db.execSQL(CREATE_STUDENT); 58 59 db.execSQL(CREATE_TEACHER); 60 61 } 62 63 64 65 @Override 66 67 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 68 69 70 71 } 72 73 }
第二步:编写自己的ContentProvider类,继承自ContentProvider类,并实现主要的方法:
1 1)编写MyContentProvider继承自ContentProvider类: 2 3 public class MyContentProvider extends ContentProvider { 4 5 6 7 @Override 8 9 public int delete (Uri uri, String selection, String[] selectionArgs) { 10 11 // TODO Auto-generated method stub 12 13 return 0; 14 15 } 16 17 18 19 @Override 20 21 public String getType(Uri uri) { 22 23 // TODO Auto-generated method stub 24 25 return null; 26 27 } 28 29 30 31 @Override 32 33 public Uri insert (Uri uri, ContentValues values){ 34 35 // TODO Auto-generated method stub 36 37 return null; 38 39 } 40 41 42 43 @Override 44 45 public boolean onCreate() { 46 47 // TODO Auto-generated method stub 48 49 return false; 50 51 } 52 53 54 55 @Override 56 57 public Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 58 59 // TODO Auto-generated method stub 60 61 return null; 62 63 } 64 65 66 67 @Override 68 69 public int update (Uri uri, ContentValues values, String selection, String[] selectionArgs) { 70 71 // TODO Auto-generated method stub 72 73 return 0; 74 75 } 76 77 }
2)注意,四大组件都需要在Manifest.xml文件中注册:
在Application节点中添加:
1 <provider android:name="cn.csc.content_provider.MyContentProvider" 2 3 android:authorities="cn.csc.content_provider"></provider>
3)为该类添加一个静态UriMatcher字段,用于后续工作中Uri的匹配工作,并通过静态代码块,添加能够匹配的Uri:
1 private static final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); 2 3 private static final int STUDENT_DIR = 0; 4 5 private static final int STUDENT_ITEM = 1; 6 7 private static final int TEACHER_DIR = 2; 8 9 private static final int TEACHER_ITEM = 3; 10 11 static{ 12 13 matcher.addURI("cn.csc.content_provider", "t_student", STUDENT_DIR); 14 15 matcher.addURI("cn.csc.content_provider", "t_student/#", STUDENT_ITEM); 16 17 matcher.addURI("cn.csc.content_provider", "t_teacher", TEACHER_DIR); 18 19 matcher.addURI("cn.csc.content_provider", "t_teacher/#", TEACHER_ITEM); 20 21 }
4)实现父类中的几个抽象方法:
1 @Override 2 3 public int delete (Uri uri, String selection, String[] selectionArgs) { 4 5 int cnt = -1; 6 7 switch(matcher.match(uri)){ 8 9 case STUDENT_DIR: 10 11 cnt = db.delete("t_student", selection, selectionArgs); 12 13 break; 14 15 case STUDENT_ITEM: 16 17 long id = ContentUris.parseId(uri); 18 19 cnt = db.delete("t_student", "id = ?", new String[]{id+""}); 20 21 break; 22 23 case TEACHER_DIR: 24 25 cnt = db.delete("t_teacher", selection, selectionArgs); 26 27 break; 28 29 case TEACHER_ITEM: 30 31 long id1 = ContentUris.parseId(uri); 32 33 cnt = db.delete("t_teacher", "id = ?", new String[]{id1+""}); 34 35 break; 36 37 } 38 39 return cnt; 40 41 } 42 43 44 45 @Override 46 47 public String getType(Uri uri) { 48 49 switch(matcher.match(uri)){ 50 51 case STUDENT_ITEM: 52 53 return "vnd.android.cursor.item/student"; 54 55 case TEACHER_ITEM: 56 57 return "vnd.android.cursor.item/teacher"; 58 59 case STUDENT_DIR: 60 61 return "vnd.android.cursor.dir/student"; 62 63 case TEACHER_DIR: 64 65 return "vnd.android.cursor.dir/teacher"; 66 67 } 68 69 return null; 70 71 } 72 73 74 75 @Override 76 77 public Uri insert (Uri uri, ContentValues values){ 78 79 80 81 switch(matcher.match(uri)){ 82 83 case STUDENT_DIR: 84 85 long id = db.insert("t_student", null, values); 86 87 return ContentUris.withAppendedId(uri, id); 88 89 case TEACHER_DIR: 90 91 return ContentUris.withAppendedId(uri, db.insert("t_teacher", null, values)); 92 93 } 94 95 return null; 96 97 } 98 99 100 101 @Override 102 103 public boolean onCreate() { 104 105 helper = new MySqliteHelper(getContext(), "students.db", null, 1); 106 107 db = helper.getWritableDatabase(); 108 109 return true; 110 111 } 112 113 114 115 @Override 116 117 public Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 118 119 Cursor cursor = null; 120 121 switch (matcher.match(uri)) { 122 123 case STUDENT_ITEM: 124 125 long id = ContentUris.parseId(uri); 126 127 cursor = db.query("t_student", projection, "id = ?", new String[]{id+""}, null, null, sortOrder); 128 129 break; 130 131 case TEACHER_ITEM: 132 133 long id1 = ContentUris.parseId(uri); 134 135 cursor = db.query("t_teacher", projection, "id = ?", new String[]{id1+""}, null, null, sortOrder); 136 137 break; 138 139 case STUDENT_DIR: 140 141 cursor = db.query("t_student", projection, selection, selectionArgs, null, null, sortOrder); 142 143 break; 144 145 case TEACHER_DIR: 146 147 cursor = db.query("t_teacher", projection, selection, selectionArgs, null, null, sortOrder); 148 149 break; 150 151 } 152 153 return cursor; 154 155 } 156 157 158 159 @Override 160 161 public int update (Uri uri, ContentValues values, String selection, String[] selectionArgs) { 162 163 int cnt = -1; 164 165 switch (matcher.match(uri)) { 166 167 case STUDENT_ITEM: 168 169 long id = ContentUris.parseId(uri); 170 171 cnt = db.update("t_student", values, "id = ?", new String[]{id+""}); 172 173 break; 174 175 case TEACHER_ITEM: 176 177 long id1 = ContentUris.parseId(uri); 178 179 cnt = db.update("t_teacher", values, "id = ?", new String[]{id1+""}); 180 181 break; 182 183 case STUDENT_DIR: 184 185 cnt = db.update("t_student", values, selection, selectionArgs); 186 187 break; 188 189 case TEACHER_DIR: 190 191 cnt = db.update("t_teacher", values, selection, selectionArgs); 192 193 break; 194 195 } 196 197 return cnt; 198 199 }
5)新建一个项目,在其中通过ContentResolver访问该ContentProvider提供的数据:
1 public class MyTest extends AndroidTestCase { 2 3 public void testInsert(){ 4 5 Uri uri = Uri.parse("content://cn.csc.content_provider/t_student"); 6 7 ContentValues values = new ContentValues(); 8 9 values.put("name", "dqrcsc"); 10 11 values.put("gender", "male"); 12 13 values.put("age", 24); 14 15 Uri uri2 = getContext().getContentResolver().insert(uri, values); 16 17 Log.i("Test",uri2.toString()); 18 19 } 20 21 public void testUpdate(){ 22 23 Uri uri = Uri.parse("content://cn.csc.content_provider/t_student/2"); 24 25 ContentValues values = new ContentValues(); 26 27 values.put("name", "bbbb"); 28 29 values.put("gender", "female"); 30 31 values.put("age", 12); 32 33 int i = getContext().getContentResolver().update(uri, values, null, null); 34 35 Log.i("Test",i+""); 36 37 } 38 39 public void testQuery(){ 40 41 Uri uri = Uri.parse("content://cn.csc.content_provider/t_student/3"); 42 43 Cursor cursor = getContext().getContentResolver().query(uri, new String[]{"id","name","gender","age"}, null, null, null); 44 45 while(cursor != null && cursor.moveToNext()){ 46 47 Log.i("Test",cursor.getString(0)+","+cursor.getString(1)+","+cursor.getString(2)+","+cursor.getString(3)); 48 49 } 50 51 } 52 53 public void testQueryAll(){ 54 55 Uri uri = Uri.parse("content://cn.csc.content_provider/t_student"); 56 57 Cursor cursor = getContext().getContentResolver().query(uri, new String[]{"id","name","gender","age"}, null, null, null); 58 59 while(cursor != null && cursor.moveToNext()){ 60 61 Log.i("Test",cursor.getString(0)+","+cursor.getString(1)+","+cursor.getString(2)+","+cursor.getString(3)); 62 63 } 64 65 } 66 67 public void testDelete(){ 68 69 Uri uri = Uri.parse("content://cn.csc.content_provider/t_student/6"); 70 71 int i = getContext().getContentResolver().delete(uri, null, null); 72 73 Log.i("Test",i+""); 74 75 } 76 77 }
以上,就是ContentProvider的简单使用。