场景:B应用程序访问A应用程序的数据库
1、A应用程序自定义一个类,继承ContentProvider,相当于对外提供了一个访问的接口。
(1)A应用程序的Manifest.xml文件中声明,代码如下。
name:provider的全名
authorities:主机名,自由命名
exported:true表示能和其他应用程序能交互
<provider
android:name="com.example.sqlitedemo.MyContentProvider"
android:authorities="com.example.sqlitedemo.MyContentProvider"
android:exported="true"/>
(2)MyContentProvider类
public class MyContentProvider extends ContentProvider {
//主机名
private static final String authority = "com.example.sqlitedemo.MyContentProvider";
private static final int INSERT_CODE = 0;
private static final int DELETE_CODE = 1;
private static final int UPDATE_CODE = 2;
private static final int QUERY_CODE = 3;
private static final int QUERY_ITEM_CODE = 4;
private static UriMatcher uriMatcher;
private MySQLiteHelper mySQLiteHelper;
static {
// Uri匹配对象,不匹配则返回-1
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 路径是 content://com.example.sqlitedemo.MyContentProvider/person/insert
//匹配成功则返回 INSERT_CODE
uriMatcher.addURI(authority, "person/insert", INSERT_CODE);
uriMatcher.addURI(authority, "person/delete", DELETE_CODE);
uriMatcher.addURI(authority, "person/update", UPDATE_CODE);
uriMatcher.addURI(authority, "person/query", QUERY_CODE);
// #是数字通配符
// 路径是 content://com.example.sqlitedemo.MyContentProvider/person/query/10
uriMatcher.addURI(authority, "person/query/#", QUERY_ITEM_CODE);
}
@Override
public boolean onCreate() {
mySQLiteHelper = new MySQLiteHelper(getContext(), "test.db", null, 1);
return false;
}
//删除操作时,会调用该方法
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
if (uriMatcher.match(arg0) == DELETE_CODE) {
SQLiteDatabase db = mySQLiteHelper.getWritableDatabase();
if (db.isOpen()) {
int position = db.delete("person", arg1, arg2);
db.close();
return position;
}
}
return 0;
}
//增加操作时,会调用该方法
@Override
public Uri insert(Uri arg0, ContentValues arg1) {
if (uriMatcher.match(arg0) == INSERT_CODE) {
SQLiteDatabase db = mySQLiteHelper.getWritableDatabase();
if (db.isOpen()) {
db.insert("person", null, arg1);
db.close();
}
}
return null;
}
//查询操作时,会调用该方法
@Override
public Cursor query(Uri uri, String[] arg1, String arg2, String[] arg3,
String arg4) {
SQLiteDatabase db = mySQLiteHelper.getReadableDatabase();
if (uriMatcher.match(uri) == QUERY_CODE) {
// 查询全部
if (db.isOpen()) {
Cursor cursor = db.query("person", arg1, arg2, arg3, null,
null, arg4);
return cursor;
// 不可以关闭数据库
}
} else if (uriMatcher.match(uri) == QUERY_ITEM_CODE) {
// 查询单条数据
if (db.isOpen()) {
// 得到Uri尾部追加的ID
long parseId = ContentUris.parseId(uri);
Cursor cursor = db.query("person", arg1, "_id = ?",
new String[] { parseId + "" }, null, null, arg4);
return cursor;
}
}
return null;
}
//更新操作时,会调用该方法
@Override
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
if (uriMatcher.match(arg0) == UPDATE_CODE) {
SQLiteDatabase db = mySQLiteHelper.getWritableDatabase();
if (db.isOpen()) {
int position = db.update("person", arg1, arg2, arg3);
db.close();
return position;
}
}
return 0;
}
//获得传进来的URI类型
@Override
public String getType(Uri arg0) {
// TODO Auto-generated method stub
return null;
}
}
2、B应用程序获得ContentResolver,然后进行访问。
<span style="white-space:pre"> </span>@Override
public void onClick(View arg0) {
// 获得ContentResolver对象,由该对象访问ContentProvider
ContentResolver contentResolver = getContentResolver();
switch (arg0.getId()) {
case R.id.insert:
//增加操作
ContentValues contentValues = new ContentValues();
contentValues.put("name", "duncan");
contentValues.put("age", 30);
//把字符串解析为Uri对象,该字符串就是我们ContentProvider对外提供的访问路径
Uri uriInsert = Uri
.parse("content://com.example.sqlitedemo.MyContentProvider/person/insert");
contentResolver.insert(uriInsert, contentValues);
break;
case R.id.delete:
//删除操作
Uri uriDelete = Uri
.parse("content://com.example.sqlitedemo.MyContentProvider/person/delete");
contentResolver.delete(uriDelete, "_id = ?",
new String[] { String.valueOf(1) });
break;
case R.id.update:
//更新操作
Uri uriUpdate = Uri
.parse("content://com.example.sqlitedemo.MyContentProvider/person/update");
ContentValues cv = new ContentValues();
cv.put("name", "helloworld");
contentResolver.update(uriUpdate, cv, "_id = ?",
new String[] { String.valueOf(2) });
break;
case R.id.query:
//查询全部操作
Uri uriQuery = Uri
.parse("content://com.example.sqlitedemo.MyContentProvider/person/query");
Cursor cursor = contentResolver.query(uriQuery, new String[] {
"name", "age" }, null, null, null);
if (cursor != null && cursor.getCount() > 0) {
while (cursor.moveToNext()) {
String name = cursor.getString(0);
int age = cursor.getInt(1);
Log.i("TAG", "name:" + name + "...age:" + age);
}
//关闭Cursor对象
cursor.close();
}
break;
case R.id.queryItem:
//查询单条数据操作
Uri uriItem = Uri
.parse("content://com.example.sqlitedemo.MyContentProvider/person/query/#");
//ContentUris类的withAppendedId方法能把该Uri后面的#号替换成3
//实际路径为 content://com.example.sqlitedemo.MyContentProvider/person/query/3
Uri newUri = ContentUris.withAppendedId(uriItem, 3);
Cursor cursorItem = contentResolver.query(newUri, new String[] {
"name", "age" }, null, null, null);
if (cursorItem != null && cursorItem.moveToFirst()) {
String name = cursorItem.getString(0);
int age = cursorItem.getInt(1);
Log.i("TAG", "name:" + name + "...age:" + age);
cursorItem.close();
}
break;
default:
break;
}
}
3、权限问题
A应用程序的Provider访问权限设置为
<provider
android:name="com.example.sqlitedemo.MyContentProvider"
android:authorities="com.example.sqlitedemo.MyContentProvider"
android:readPermission="aa.read"
android:writePermission="aa.write"
android:exported="true"/>
由于aa.read和aa.write是自定义的,所以必须要进行声明。即在本Manifest.xml文件中,加上:
<permission android:name="aa.read" />
<permission android:name="aa.write" />
<uses-permission android:name="aa.read"/>
<uses-permission android:name="aa.write"/>
4、观察者ContentObserver
该类主要是用来监听数据库的变化,比如往该数据库上增加一条数据之类的,都能监听到。
(1)B应用程序注册一个监听器
/**
* 注册一个内容观察者
* Uri:要监听观察的Uri
* notifyForDescendents:该Uri的子Uri是否也要观察监听
* ContentObserver抽象类对象
*/
getContentResolver()
.registerContentObserver(
Uri.parse("content://com.example.sqlitedemo.MyContentProvider"),
true, new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
// TODO Auto-generated method stub
super.onChange(selfChange);
Log.i(TAG, "数据发生变化了...");
}
});
(2)A应用程序发出通知。
// 增加操作时,会调用该方法
@Override
public Uri insert(Uri arg0, ContentValues arg1) {
if (uriMatcher.match(arg0) == INSERT_CODE) {
SQLiteDatabase db = mySQLiteHelper.getWritableDatabase();
if (db.isOpen()) {
db.insert("person", null, arg1);
//通知观察者,数据变化了
getContext()
.getContentResolver()
.notifyChange(
Uri.parse("content://com.example.sqlitedemo.MyContentProvider"),
null);
db.close();
}
}
return null;
}