理论概述
为什么要有ContentProvider?
- 功能需求: 一个应用需要访问另一个应用的数据库表数据
- 实际情况: 一个应用的数据库文件是应用私有的, 其它应用不能直接访问
ContentProvider是什么?
- ContentProvider是四大应用组件之一
- 当前应用使用ContentProvider将数据库表数据操作暴露给其它应用访问
- 其它应用需要使用ContentResolver来调用ContentProvider的方法
- 它们之间的调用是通过Uri来进行交流的
相关API
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);
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)
Uri: 包含请求地址数据的类
//得到其对象
Uri static parse(String uriString)
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)
案例一:自定义两个应用
定义一个provide项目
首先定义一个数据库操作类
public class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context) {
super(context, "dongge2.db", 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) {
}
}
自定义一个provider:将自己的数据库表数据暴露给其他应用使用
public class PersonProvider extends ContentProvider {
private DBHelper dbHelper;
//用来存放所有合法的Uri的容器
private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
private int deleteCount;
public PersonProvider() {
Log.e("TAG", "PersonProvider()");
}
//保存一些合法的uri
//contetn://com.hbwj.serviceclient.personprovider/person不根据id操作
//contetn://com.hbwj.serviceclient.personprovider/person/1根据id操作
static {
matcher.addURI("com.hbwj.serviceclient.personprovider", "/person", 1);
matcher.addURI("com.hbwj.serviceclient.personprovider", "/person/#", 2);//#匹配任意数字
}
@Override
public boolean onCreate() {
Log.e("TAG", "PersonProvider onCreate()");
dbHelper = new DBHelper(getContext());
return false;
}
//contetn://com.hbwj.serviceclient.personprovider/person 不根据id查询
//contetn://com.hbwj.serviceclient.personprovider/person/1根据id查询
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder) {
Log.e("TAG", "PersonProvider query()");
//得到连接对象
SQLiteDatabase database = dbHelper.getReadableDatabase();
//匹配url,返回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) {//根据id查询
long id = ContentUris.parseId(uri);
Cursor cursor = database.query("person", null, "_id=?", new String[]{id + ""}, null, null, null);
return cursor;
} else {//如果不合法抛出异常
throw new RuntimeException("查询的uri不合法");
}
}
//contetn://com.hbwj.serviceclient.personprovider/person 不根据id插入
//contetn://com.hbwj.serviceclient.personprovider/person/1根据id插入(没有)
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
Log.e("TAG", "PersonProvider insert()");
//得到连接对象
SQLiteDatabase database = dbHelper.getReadableDatabase();
//匹配url,返回code
int code = matcher.match(uri);
//如果合法, 进行插入
if (code == 1) {
long id = database.insert("person", null, values);
//将id添加到uri中
uri = ContentUris.withAppendedId(uri, id);
database.close();
return uri;
} else {
//如果不合法抛出异常
database.close();
throw new RuntimeException("插入uri不合法");
}
}
//contetn://com.hbwj.serviceclient.personprovider/person 不根据id删除
//contetn://com.hbwj.serviceclient.personprovider/person/1根据id删除
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
Log.e("TAG", "PersonProvider delete()");
//得到连接对象
SQLiteDatabase database = dbHelper.getReadableDatabase();
//匹配url,返回code
int code = matcher.match(uri);
//如果合法, 进行删除
int deleteCount = 0;
if (code == 1) {//不根据id删除
deleteCount = database.delete("person", selection, selectionArgs);
} else if (code == 2) {//根据id删除
long id = ContentUris.parseId(uri);
deleteCount = database.delete("person", "_id=" + id, null);
} else {
//如果不合法, 抛出异常
database.close();
throw new RuntimeException("刪除的uri不合法");
}
return deleteCount;
}
//contetn://com.hbwj.serviceclient.personprovider/person 不根据id更新
//contetn://com.hbwj.serviceclient.personprovider/person/1根据id更新
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
Log.e("TAG", "PersonProvider update()");
//得到连接对象
SQLiteDatabase database = dbHelper.getReadableDatabase();
//匹配url,返回code
int code = matcher.match(uri);
//如果合法, 进行删除
int updateCount = 0;
if (code == 1) {//不根据id更新
updateCount = database.update("person", values, selection, selectionArgs);
} else if (code == 2) {//根据id更新
long id = ContentUris.parseId(uri);
updateCount = database.update("person", values, "_id=" + id, null);
} else {
//如果不合法, 抛出异常
database.close();
throw new RuntimeException("更新的uri不合法");
}
database.close();
return updateCount;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
}
注意:需要在项目中注册
<!--exported : 是否可以让其它应用访问 -->
<provider
android:authorities="com.hbwj.serviceclient.personprovider"
android:name=".PersonProvider"
android:exported="true"/>
自定义一个Resolver类:对Provide类中的数据库进行查询更新删除等操作
首先布局
<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>
查询操作
//1.得到ContentResolver对象
ContentResolver resolver = getContentResolver();
//2.调用query,得到cursor
Uri uri = Uri.parse("content://com.hbwj.serviceclient.personprovider/person/1");
uri = Uri.parse("content://com.hbwj.serviceclient.personprovider/person");
Cursor cursor = resolver.query(uri, null, null, null, null, null);
//3.取出其中的值并显示
if (cursor != null) {
while (cursor.moveToNext()) {
int id = cursor.getInt(0);
String name = cursor.getString(1);
Toast.makeText(this, "id==" + id + "name==" + name, Toast.LENGTH_SHORT).show();
}
}
删除操作
//1.得到ContentResolver对象
ContentResolver resolver = getContentResolver();
//2.调用delete
Uri uri = Uri.parse("content://com.hbwj.serviceclient.personprovider/person/1");
int deleteCount = resolver.delete(uri, null, null);
Toast.makeText(this, "deleteCount="+deleteCount, 1).show();
更新操作
//1.得到ContentResolver对象
ContentResolver resolver = getContentResolver();
//2.调用update
Uri uri = Uri.parse("content://com.hbwj.serviceclient.personprovider/person/2");
ContentValues values=new ContentValues();
values.put("name","jack2");
int updateCount = resolver.update(uri, values, null, null);
Toast.makeText(this, "updateCount="+updateCount, Toast.LENGTH_SHORT).show();
插入操作
//1.得到ContentResolver对象
ContentResolver resolver = getContentResolver();
//2.调用insert
Uri uri = Uri.parse("content://com.hbwj.serviceclient.personprovider/person");
ContentValues values = new ContentValues();
values.put("name", "jack");
uri = resolver.insert(uri, values);
Toast.makeText(this, uri.toString(), Toast.LENGTH_SHORT).show();
案例2:选择手机联系人号码
主界面布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/et_main_number"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="请输入或选择一个联系人号码" />
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/et_main_number"
android:onClick="toContactList"
android:text="选择联系人" />
</RelativeLayout>
其他布局很简单就是一个listview去显示联系人电话号码和名字,不要问我怎么还用listview,一个字懒
主布局activity代码
public void toContactList(View view) {
//启动联系人列表界面
startActivityForResult(new Intent(this, ContactListActivity.class), 1);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1 && resultCode == RESULT_OK){
String number = data.getStringExtra("NUMBER");
et_main_number.setText(number);
}
super.onActivityResult(requestCode, resultCode, data);
}
联系人列表界面代码,adapter很简单就不粘贴了
查询联系人表数据
ContentResolver resolver = getContentResolver();
String[] projcetio = new String[]{
Phone.DISPLAY_NAME,
Phone.NUMBER
};
Cursor cursor = resolver.query(Phone.CONTENT_URI, projcetio, null, null, null);
while (cursor.moveToNext()) {
String name = cursor.getString(0);
String number = cursor.getString(1);
Map<String, String> map = new HashMap<>();
map.put("name", name);
map.put("number", number);
data.add(map);
}
点击某一条返回电话号码给MainActivity界面
//得到返回的号码
String number=data.get(position).get("number");
Intent intent = getIntent();
//设置结果
intent.putExtra("NUMBER", number);
setResult(RESULT_OK,intent);
//返回
finish();
**读取联系人权限**android.permission.READ_CONTACTS