创建一个contentProvider
- 首先我们需要准备好一个数据库,创建一张表,作为操作的基本表
public class DbHelper extends SQLiteOpenHelper {
public DbHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
public DbHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version, @Nullable DatabaseErrorHandler errorHandler) {
super(context, name, factory, version, errorHandler);
}
@RequiresApi(api = Build.VERSION_CODES.P)
public DbHelper(@Nullable Context context, @Nullable String name, int version, @NonNull SQLiteDatabase.OpenParams openParams) {
super(context, name, version, openParams);
}
private String sql="create table person (id integer primary key autoincrement, name text, age integer)";
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(sql);
Log.d("sqlite","数据库创建成功");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
- 创建一个MyProvider类,让它继承自ContentProvider, 它有几个重要的成员,UriMatcher对象,它里面存放正确的uri,以及后面调用它的match方法匹配URI,数据库对象db,对数据表操作 。
private final int PERSON=1;
private final int PERSONOITEM=2;
// 数据库
private DbHelper helper;
// matcher
private UriMatcher matcher=new UriMatcher(UriMatcher.NO_MATCH);
private final String authority="com.example.demo4.myprovider";
@Override
public boolean onCreate() {
helper=new DbHelper(getContext(),"person.db",null,1);
matcher.addURI(authority,"person",PERSON);
matcher.addURI(authority,"person/#",PERSONOITEM);
return true;
}
上面我声明了两个常量PERSON, PERSONITEM, 可以把它看做是两个URI的type, 所加入的两条uri分为为
com.example.demo4.myprovider/person
com.example.demo4.myprovider.person/#
这里的#代表任意数字,如果是* 则代表匹配任意长度的任意字符。
想必你猜到了,这里的PERSON, PERSONITEM两个常量就是代表两个uri的编号。
接下来看一下查询方法
public Cursor query(@NonNull Uri uri,String[] projection,String selection, String[] selectionArgs, String sortOrder) {
// 获取数据库对象
SQLiteDatabase db=helper.getWritableDatabase();
// 匹配uri
int code = matcher.match(uri);
// 不根据id查询
if (code==PERSON){
return db.query("person",projection,selection,selectionArgs,null,null,null);
}
// 根据id查询
else if (code==PERSONOITEM){
// 解析id
long id = ContentUris.parseId(uri);
return db.query("person",projection,"id=?",new String[]{id+""},null,null,null);
}
// 错误
else {
return null;
}
}
这里通过mather对象的match方法得到查询的uri的类型,如果是查询整张表,那么code应该是PERSON, 如果是根据id查询,那么code应该是PERSONITEM,根据id查询时,调用ContentUris的parseId()方法来解析出查询的id。
- 在AndroidManifest.xml文件中声明我们的provider。
<provider
android:authorities="com.example.demo4.myprovider"
android:name=".MyProvider"
android:enabled="true"
android:exported="true"/>
authorities属性是其他应用查找该provider的依据,一般这里用provider的全类名小写即可。
Uri对象所对应的MIME类型
**getType()**方法用于获取URI对象所对应MIME类型,一个内容URI的MIME 类型由3个部分组成。
- 以vnd开头
- 如果内容URL以路径结尾,那么后接android.cursor.dir/; 如果内容URL以id结尾,那么后接android.cursor.item/;
- 最后还要接上vnd..
比如上文中,我们的URI是com.example.demo4.myprovider/person,它所对应的MIME类型是
vnd.android.cursor.dir/vnd.com.example.demo4.myprovider.person
其他应用中使用
Uri uri=Uri.parse("content://com.example.demo4.myprovider/person/1");
Cursor cursor = getContentResolver().query(uri,null,null,null,null);
if (cursor.moveToFirst()){
do{
String name = cursor.getString(cursor.getColumnIndex("name"));
int age = cursor.getInt(cursor.getColumnIndex("age"));
Log.d("query","name: "+name+" age: "+age);
}while (cursor.moveToNext());
}
在API 30之后,android又对ContentProvider做出了限制,也就是查询的一方必须在AndroidManifest.xml 中声明要查询的provider,否则查询不到。
<queries>
<provider android:authorities="com.ts.schedule.myprovider"/>
</queries>
总结
- ContentProvider必须在AndroidManifest.xml文件中声明,并且指定export为true,authorities一般指定为全类名小写即可。
- UriMatcher类负责存储和匹配uri。