你的位置:首页 > 操作系统

[操作系统]android菜鸟学习笔记21


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    @Override42 43    public void onOpen(SQLiteDatabase db) {44 45      Log.i(TAG,"open db");46 47      super.onOpen(db);48 49    }50 51 52 53    @Override54 55    public void onCreate(SQLiteDatabase db) {56 57       db.execSQL(CREATE_STUDENT);58 59       db.execSQL(CREATE_TEACHER);60 61    }62 63 64 65    @Override66 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 stub12 13      return 0;14 15    }16 17 18 19    @Override20 21    public String getType(Uri uri) {22 23      // TODO Auto-generated method stub24 25      return null;26 27    }28 29 30 31    @Override32 33    public Uri insert (Uri uri, ContentValues values){34 35      // TODO Auto-generated method stub36 37      return null;38 39    }40 41 42 43    @Override44 45    public boolean onCreate() {46 47      // TODO Auto-generated method stub48 49      return false;50 51    }52 53 54 55    @Override56 57    public Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {58 59      // TODO Auto-generated method stub60 61      return null;62 63    }64 65 66 67    @Override68 69    public int update (Uri uri, ContentValues values, String selection, String[] selectionArgs) {70 71      // TODO Auto-generated method stub72 73      return 0;74 75    }76 77 }

2)注意,四大组件都需要在Manifest.

在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    @Override102 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    @Override116 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    @Override160 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的简单使用。