一、理论概述
1、为什么要有ContentProvider?
功能需求: 一个应用需要访问另一个应用的数据库表数据
实际情况: 一个应用的数据库文件是应用私有的, 其它应用不能直接访问。
2、ContentProvider是什么?
ContentProvider是四大应用组件之一
当前应用使用ContentProvider将数据库表数据操作暴露给其它应用访问
其它应用需要使用ContentResolver来调用ContentProvider的方法
它们之间的调用是通过Uri来进行交流的
3、相关API (1)
ContentProvider : 内容提供者类
//provider对象创建后调用(应用安装成功或手机启动完成)
public abstract boolean onCreate();
//查询表数据
Cursor query(Uri uri, String[] projection,String selection, String[] selectionArgs)
//插入表数据
Uri insert(Uri uri, ContentValues values);
//删除表数据
int delete(Uri uri, String selection, String[] selectionArgs)
//更新表数据
update(Uri uri, ContentValues values, String selection,String[] selectionArgs);
4、相关API (2)
ContentResolver: 内容提供者的解析类
//得到它的对象
context.getContentResolver()
//调用provider进行数据库CRUD操作
Insert()、delete()、update()、query()
//注册uri的监听
registerContentObserver(Uri uri, boolean notify,ContentObserver observer)
//解注册uri的监听
unregisterContentObserver(ContentObserver observer)
//通知监听器
notifyChange(Uri uri, ContentObserver observer)
5、相关API (3)
Uri: 包含请求地址数据的类
//得到其对象
Uri static parse(String uriString)
A : 是一个前缀,表示是由ContentProvider提供,固定不变
B : authority, 标识是哪个Provider,不同的Provider此部分必须不同。
C : 对应于哪张表 student
D : id值, 对应表中的哪条记录
6、相关API (4)
UriMatcher : 用于匹配Uri的容器
//添加一个合法的URI
void addURI(String authority, String path, int code)
//匹配指定的uri, 返回匹配码
int match(Uri uri)
ContentUris : 解析uri的工具类
//解析uri, 得到其中的id
long parseId(Uri contentUri)
//添加id到指定的uri中
Uri withAppendedId(Uri contentUri, long id)
二、ContentProvider开发
1、 基本步骤
(1)编写ContentProvider子类
class StudentContentProvider extends ContentProvider {
//实现inert、delete、update和query等方法
}
(2)在manifest.xml中注册
<provider
android:name=".StudentContentProvider"
android:authorities="com.atguigu.provider.studentprovider"
android:exported="true"/>
2、基本步骤
(1)得到其对象
context.getContentResolver()
(2)使用其对象
inert()、delete()、update()和query()
系统自动找到匹配的ContentProvider对象来操作数据
registerContentObserver(Uri uri, boolean notify,ContentObserver observer)
注册uri的监听
unregisterContentObserver(ContentObserver observer)
解注册uri的监听
notifyChange(Uri uri, ContentObserver observer)
通知监听器
实现原理:被调用端继承ContentProvider实现数据库的增删改查,然后再AndroidManifest.xml注册peovider。调用端用ContentResolver通过Uri调用被调用端的ContentProvider。
三、实例 被调用端 ContentProvider
在这个文件中实现数据库的增删改查
/**
* person数据表的ContentProvoder
*/
public class PersonProvider extends ContentProvider {
//用来存放所有合法的Uri的容器
private static UriMatcher matcher=new UriMatcher(UriMatcher.NO_MATCH);
//保存一些合法的uri
// content://com.example.contentprovider.PersonProvider/person 不根据id操作
// content://com.example.contentprovider.PersonProvider/person/3 根据id操作
static{
matcher.addURI("com.example.contentprovider.PersonProvider","/person",1);
matcher.addURI("com.example.contentprovider.PersonProvider","/person/#",2); //#匹配任意数字
}
private DBHelper dbHelper;
public PersonProvider() {
Log.e("TAG", "PersonProvider()");
}
@Override
public boolean onCreate() {
Log.e("TAG", "PersonProvider onCreate()");
dbHelper=new DBHelper(getContext());
return false;
}
// content://com.example.contentprovider.PersonProvider/person 不根据id查询
// content://com.example.contentprovider.PersonProvider/person/3 根据id查询
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Log.e("TAG", "PersonProvider query()");
//得到数据库连接对象
SQLiteDatabase database=dbHelper.getReadableDatabase();
//1.匹配uri, 返回code
int code=matcher.match(uri);
//如果合法, 进行查询
if(code==1){//不根据id查询
Cursor cursor=database.query("person",projection,selection,selectionArgs,null,null,null);
return cursor;
}else if(code==2){
long id= ContentUris.parseId(uri);
Cursor cursor=database.query("person",projection,"_id=?",new String[]{id+""},null,null,null);
return cursor;
}
return null;
}
@Override
public String getType(@NonNull Uri uri) {
return null;
}
// content://com.example.contentprovider.PersonProvider/person 插入
// content://com.example.contentprovider.PersonProvider/person/3 根据id插入(没有)
@Override
public Uri insert(Uri uri, ContentValues values) {
Log.e("TAG", "PersonProvider insert()");
//得到数据库连接对象
SQLiteDatabase database=dbHelper.getReadableDatabase();
//1.匹配uri, 返回code
int code=matcher.match(uri);
//如果合法, 进行插入
if(code==1){//不根据id查询
long id=database.insert("person",null,values);
uri=ContentUris.withAppendedId(uri,id);
database.close();
return uri;
}else{
//如果不合法, 抛出异常
database.close();
throw new RuntimeException("插入的uri不合法");
}
}
// content://com.example.contentprovider.PersonProvider/person 不根据id删除
// content://com.example.contentprovider.PersonProvider/person/3 根据id删除
@Override
public int delete(Uri uri, String selection,String[] selectionArgs) {
Log.e("TAG", "PersonProvider delete()");
//得到数据库连接对象
SQLiteDatabase database=dbHelper.getReadableDatabase();
//1.匹配uri, 返回code
int code=matcher.match(uri);
int deleteCount=-1;
//如果合法, 进行删除
if(code==1){//不根据删除
deleteCount= database.delete("person",selection,selectionArgs);
}else if(code==2){//根据id删除
long id= ContentUris.parseId(uri);
deleteCount= database.delete("person","_id=?",new String[]{id+""});
}else{
database.close();
//如果不合法, 抛出异常
throw new RuntimeException("删除的uri不合法");
}
database.close();
return deleteCount;
}
// content://com.example.contentprovider.PersonProvider/person 不根据id更新
// content://com.example.contentprovider.PersonProvider/person/3 根据id更新
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
Log.e("TAG", "PersonProvider update()");
//得到数据库连接对象
SQLiteDatabase database=dbHelper.getReadableDatabase();
//1.匹配uri, 返回code
int code=matcher.match(uri);
int updateCount=-1;
//如果合法, 进行更新
if(code==1){//不根据删除更新
updateCount=database.update("person",values,selection,selectionArgs);
}else if (code==2){
long id=ContentUris.parseId(uri);
updateCount=database.update("person",values,"_id="+id,null);
}else{
//如果不合法, 抛出异常
throw new RuntimeException("更新的uri不合法");
}
database.close();
return updateCount;
}
}
数据库帮助类
/**
* 数据库帮助类
*/
public class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context) {
super(context, "haitao", null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.e("TAG", "onCreate()...");
//建表
db.execSQL("create table person(_id integer primary key autoincrement, name varchar)");
//插入初始化数据
db.execSQL("insert into person (name) values ('Tom')");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
AndroidManifest.xml
<provider
android:name=".PersonProvider"
android:authorities="com.example.contentprovider.PersonProvider"
android:exported="true">
<!-- exported : 是否可以让其它应用访问 -->
</provider>
四、调用端 ContentResolver
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//通过ContentResolver调用ContentProvider插入一条记录
public void insert(View v){
//1. 得到ContentResolver对象
ContentResolver resolver=getContentResolver();
//2. 调用其insert
Uri uri=Uri.parse("content://com.example.contentprovider.PersonProvider/person");
ContentValues values=new ContentValues();
values.put("name","haitao");
uri = resolver.insert(uri,values);
Toast.makeText(this, uri.toString(),Toast.LENGTH_SHORT).show();
}
//通过ContentResolver调用ContentProvider更新一条记录
public void update(View v){
//1. 得到ContentResolver对象
ContentResolver resolver=getContentResolver();
//2. 调用其update
Uri uri=Uri.parse("content://com.example.contentprovider.PersonProvider/person/2");//更新person表的id为2的数据
ContentValues values=new ContentValues();
values.put("name","jack");
int updateCount =resolver.update(uri,values,null,null);
Toast.makeText(this, "updateCount="+updateCount,Toast.LENGTH_SHORT).show();
}
//通过ContentResolver调用ContentProvider删除一条记录
public void delete(View v){
//1. 得到ContentResolver对象
ContentResolver resolver=getContentResolver();
//2. 调用其delete
Uri uri=Uri.parse("content://com.example.contentprovider.PersonProvider/person/2");//删除person表的id为2的数据
int deleteCount=resolver.delete(uri,null,null);
Toast.makeText(this, "deleteCount="+deleteCount, Toast.LENGTH_SHORT).show();
}
//通过ContentResolver调用ContentProvider查询所有记录
public void query(View v){
//1. 得到ContentResolver对象
ContentResolver resolver=getContentResolver();
2. 调用其query, 得到cursor
Uri uri=Uri.parse("content://com.example.contentprovider.PersonProvider/person/2");//查询person表的id为2的记录
uri=Uri.parse("content://com.example.contentprovider.PersonProvider/person");//查询所有记录
Cursor cursor=resolver.query(uri,null,null,null,null);
while(cursor.moveToNext()){
int id=cursor.getInt(0);//获取_id的值
String name=cursor.getString(1);//获取名字
Toast.makeText(this,id+":"+name,Toast.LENGTH_SHORT).show();
}
cursor.close();
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="insert"
android:text="INSERT" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="delete"
android:text="DELETE" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="update"
android:text="UPDATE" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="query"
android:text="QUERY" />
</LinearLayout>