1.创建自己的内容提供器
1.1 基础知识
如果想要实现跨程序共享数据的功能,官方推荐的方式就是使用内容提供器,可以通过新建一个类去继承ContentProvide
r的方式来创建一个自己的内容提供器。ContentProvider类中有6个抽象方法,我们在使用子类继承它的时候,需要将这6个方法全部重写。
1.1.1 内容URL
回顾一下,一个标准的内容URI写法是这样的:
content://com.example.app.provider/table1
这就表示调用方期望访问的是com.example.app这个应用的table1表中的数据。
除此之外,我们还可以在这个内容URI的后面加上一个id,如下所示: content://com.example.app.provider/table1/1
这就表示调用方期望访问的是com.example.app这个应用的table1表中id为1的数据。
内容URI的格式主要就只有以上两种,以路径结尾就表示期望访问该表中所有的数据,以id结尾就表示期望访问该表中拥有相应id的数据。我们可以使用通配符的方式来分别匹配这两种格式的内容URI,规则如下。
*:表示匹配任意长度的任意字符。
:表示匹配任意长度的数字。
所以,一个能够匹配任意表的内容URI格式就可以写成:
content://com.example.app.provider/*
而一个能够匹配table1表中任意一行数据的内容URI格式就可以写成:
content://com.example.app.provider/#
1.1.2 UriMatcher
接着,我们再借助UriMatcher这个类就可以轻松地实现匹配内容URI的功能。
当调用UriMatcher的match()方法时,就可以将一个Uri对象传入,返回值是某个能够匹配这个Uri对象所对应的自定义代码,利用这个代码,我们就可以判断出调用方期望访问的是哪张表中的数据了。
郭霖. 第一行代码 Android 第2版 (图灵原创) (Kindle位置4747). 人民邮电出版社. Kindle 版本.
1.1.3 getType()方法
其中方法 getType()
: 根据传入的内容URI来返回相应的MIME类型。
它是所有的内容提供器都必须提供的一个方法,用于获取Uri对象所对应的MIME类型。
一个内容URI所对应的MIME字符串主要由3部分组成,Android对这3个部分做了如下格式规定。
必须以 vnd 开头, 如果内容URI以路径结尾,则后接
android.cursor.dir/,如果内容URI以id结尾,则后接android.cursor.item/ 。
最后接上 vnd.
- 对于content://com.example.app.provider/table1这个内容URI,它所对应的MIME类型就可以写成:
vnd.android.cursor.dir/vnd.com.example.app.provider.table1
- 对于content://com.example.app.provider/table1/1这个内容URI,它所对应的MIME类型就可以写成:
vnd.android.cursor.item/vnd.com.example.app.provider.table1
2. 示例
2.1 创建内容提供器类
打开之前的工程【DatabaseDemo】,右键包名->New ->Other->Content Provider:
l类名:DatabaseContentProvider
,authority 指定为 com.example.databasedemo.provider
Exported
属性表示是否允许外部程序访问我们的内容提供器,Enabled
属性表示是否启用这个内容提供器。将两个属性都勾中,点击Finish完成创建。
修改类DatabaseContentProvider
: 实现继承ContentProvider
的6个方法
public class DatabaseContentProvider extends ContentProvider {
public static final int Book_Dir = 0;
public static final int Book_Item = 1;
public static final int Gategory_Dir = 2;
public static final int Gategory_Item = 3;
public static final String Authority = "com.example.databasedemo.provider";
private static UriMatcher uriMatcher;
private MyDatabaseHelper dbHelper;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(Authority, "book", Book_Dir);
uriMatcher.addURI(Authority, "book/#", Book_Item);
uriMatcher.addURI(Authority, "gategory", Gategory_Dir);
uriMatcher.addURI(Authority, "gategory/#", Gategory_Item);
}
public DatabaseContentProvider() {
}
@Override
public boolean onCreate() {
//获取 SQLiteOpenHelper 实例,以便操作数据库
dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, MainActivity.DataBaseVersion);
return true;
}
@Override
public String getType(Uri uri) {
//Implement this to handle requests for the MIME type of the data
// at the given URI.
switch (uriMatcher.match(uri)) {
case Book_Dir:
return "vnd.android.cursor.dir/vnd.com.example.app.provider.book";
case Book_Item:
return "vnd.android.cursor.item/vnd.com.example.app.provider.book";
case Gategory_Dir:
return "vnd.android.cursor.dir/vnd.com.example.app.provider.gategory";
case Gategory_Item:
return "vnd.android.cursor.item/vnd.com.example.app.provider.gategory";
}
return null;
}
/**
* 查询
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = null;
switch (uriMatcher.match(uri)) {
case Book_Dir:
cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder);
break;
case Book_Item:
String bookId = uri.getPathSegments().get(1); //获取Id
cursor = db.query("Book", projection, "id=?", new String[]{ bookId}, null, null, sortOrder);
break;
case Gategory_Dir:
cursor = db.query("category", projection, selection, selectionArgs, null, null, sortOrder);
break;
case Gategory_Item:
String categoryId = uri.getPathSegments().get(1); //获取Id
cursor = db.query("category", projection, "id=?", new String[]{ categoryId}, null, null, sortOrder);
break;
}
return cursor;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
Uri retunUrl = null;
switch (uriMatcher.match(uri)) {
case Book_Dir:
case Book_Item:
long newbookId = db.insert("Book", null, values);
retunUrl = Uri.parse("content://" + Authority + "/book/" + newbookId);
break;
case Gategory_Dir:
case Gategory_Item:
long newGategoryId = db.insert("Book", null, values);
retunUrl = Uri.parse("content://" + Authority + "/gategory/" + newGategoryId);
break;
}
return retunUrl;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
int updateRows = 0; //影响的行数
switch (uriMatcher.match(uri)) {
case Book_Dir:
updateRows = db.update("book", values, selection, selectionArgs);
break;
case Book_Item:
String bookId = uri.getPathSegments().get(1);
updateRows = db.update("book", values, "id=?", new String[]{ bookId});
break;
case Gategory_Dir:
updateRows = db.update("gategory", values, selection, selectionArgs);
break;
case Gategory_Item:
String gategoryId = uri.getPathSegments().get(1);
updateRows = db.update("gategory", values, "id=?", new String[]{ gategoryId});
break;
}
return updateRows;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
int deleteRows = 0; //影响的行数
switch (uriMatcher.match(uri)) {
case Book_Dir:
deleteRows = db.delete("book", selection, selectionArgs);
break;
case Book_Item:
String bookId = uri.getPathSegments().get(1);
deleteRows = db.delete("book", "id=?", new String[]{ bookId});
break;
case Gategory_Dir:
deleteRows = db.delete("gategory", selection, selectionArgs);
break;
case Gategory_Item:
String gategoryId = uri.getPathSegments().get(1);
deleteRows = db.delete("gategory", "id=?", new String[]{ gategoryId});
break;
}
return deleteRows;
}
}
2.2 注册内容提供器
Android Studio 自动在AndroidManifest.xml
自动添加:provider
标签,对内容提供器进行了注册
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.databasedemo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<provider
android:name=".DatabaseContentProvider"
android:authorities="com.example.databasedemo.provider"
android:enabled="true"
android:exported="true"></provider>
......
2.3 外部程序使用该内容提供器
新建一个项目【UsingOutsideContentProvider】
在创建4个按钮,分别用于增、删、改、查
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button android:id="@+id/btn_insert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="添加数据"/>
<Button android:id="@+id/btn_query"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="查询数据"/>
<Button android:id="@+id/btn_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="更新数据"/>
<Button android:id="@+id/btn_delete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="删除数据"/>
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private String newBookId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//添加数据
Button btn_insert = findViewById(R.id.btn_insert);
btn_insert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ContentResolver contentResolver = getContentResolver();
Uri uri = Uri.parse("content://com.example.databasedemo.provider/book/");
ContentValues values = new ContentValues();
values.put("name", "waibuchengxu");
values.put("author", "lao wai");
values.put("pages", 30);
values.put("price", 6.40);
Uri newUri = contentResolver.insert(uri, values);
newBookId = newUri.getPathSegments().get(1);
Log.d("contentProvider-data", "newBookId: " + newBookId);
values.clear();
values.put("name", "waibuchengxu-2");
values.put("author", "lao wai");
values.put("pages", 30);
values.put("price", 6.40);
Uri newUri2 = contentResolver.insert(uri, values);
String newId2 = newUri2.getPathSegments().get(1);
Log.d("contentProvider-data", "newId2: " + newId2);
}
});
//查询数据
Button btn_query = findViewById(R.id.btn_query);
btn_query.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ContentResolver contentResolver = getContentResolver();
Uri uri = Uri.parse("content://com.example.databasedemo.provider/book/");
//Cursor cursor = contentResolver.query(uri, new String[]{ "name", "price","author"}, "author=?", new String[]{"lao wai"},null);
Cursor cursor = contentResolver.query(uri, new String[]{ "id, name", "price", "author"}, null, null,null);
int index=0;
if ( cursor != null){
while (cursor.moveToNext()) {
String id = cursor.getString(cursor.getColumnIndex("id"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String price = cursor.getString(cursor.getColumnIndex("price"));
String author = cursor.getString(cursor.getColumnIndex("author"));
String msg = (++index)+". id:" + id +" | name:" + name + " | author:" + author+ " | price:" + price;
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
Log.d("contentProvider-data", msg);
}
}
cursor.close(); //记得关闭指针
}
});
//更新数据
Button btn_update = findViewById(R.id.btn_update);
btn_update.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ContentResolver contentResolver = getContentResolver();
Uri uri = Uri.parse("content://com.example.databasedemo.provider/book/");
ContentValues values = new ContentValues();
values.put("price", 100); //只更新标明的字段,其它字段值不会被修改
int updateRows = contentResolver.update(uri, values, "author=?", new String[]{"lao wai"});
Log.d("contentProvider-data", "影响行数:"+updateRows );
}
});
//删除数据
Button btn_delete = findViewById(R.id.btn_delete);
btn_delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ContentResolver contentResolver = getContentResolver();
Uri uri = Uri.parse("content://com.example.databasedemo.provider/book/");
int deleteRows = contentResolver.delete(uri, "name=?", new String[]{"waibuchengxu-2"});
Log.d("contentProvider-data", "book/ 影响行数:"+ deleteRows );
Log.d("contentProvider-data", "newBookId: " + newBookId);
Uri uriItem = Uri.parse("content://com.example.databasedemo.provider/book/" + newBookId);
int deleteItemRows = contentResolver.delete(uriItem, null, null);
Log.d("contentProvider-data", "book/id:影响行数:"+ deleteItemRows );
}
});
}
}
2.3.1使用要点
-
获取
ContentResolver
:ContentResolver contentResolver = getContentResolver();
-
创建Uri:
- 面向全表:
Uri uri = Uri.parse("content://com.example.databasedemo.provider/book/");
- 面向某行:
Uri uri = Uri.parse("content://com.example.databasedemo.provider/book/id");
- 面向全表:
-
增:
Uri newUri = contentResolver.insert(uri,...)
; -
删:
int rows =contentResolver.delete(uri,...)
; -
改:
int rows = contentResolver.update(uri,...);
-
查:
Cursor cursor = contentResolver.query(uri,...)
;