第二篇来看看ContentProvider,就是把我们的内容提供给别人,让别人来使用。那么我们这里就需要两个项目,一个是包含数据库用来提供数据的,一个是用来调用查看的。首先看下提供数据的工程:
创建数据库的代码:
public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK = "create table Book ("
+ "id integer primary key autoincrement,"
+ "author text,"
+ "price real,"
+ "pages integer,"
+ "name text )";
public static final String CREATE_CATEGORY = "create table Category (" +
"id integer primary key autoincrement," +
"category_name text," +
"category_code integer)";
private Context mContext;
public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
this.mContext = context;
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(CREATE_BOOK);
sqLiteDatabase.execSQL(CREATE_CATEGORY);
// Toast.makeText(mContext , "创建成功" , Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
sqLiteDatabase.execSQL("drop table if exists Book");
sqLiteDatabase.execSQL("drop table if exists Category");
onCreate(sqLiteDatabase);
}
}
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button bt_create_database;
private MyDatabaseHelper myDatabaseHelper;
private Button bt_insert_data;
private Button bt_update_data;
private Button bt_delete_data;
private Button bt_query_data;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
bt_create_database = (Button) findViewById(R.id.bt_create_database);
bt_create_database.setOnClickListener(this);
myDatabaseHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
bt_insert_data = (Button) findViewById(R.id.bt_insert_data);
bt_insert_data.setOnClickListener(this);
bt_update_data = (Button) findViewById(R.id.bt_update_data);
bt_update_data.setOnClickListener(this);
bt_delete_data = (Button) findViewById(R.id.bt_delete_data);
bt_delete_data.setOnClickListener(this);
bt_query_data = (Button) findViewById(R.id.bt_query_data);
bt_query_data.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_create_database:
myDatabaseHelper.getWritableDatabase();
break;
case R.id.bt_insert_data:
insertData();
break;
case R.id.bt_update_data:
updateData();
break;
case R.id.bt_delete_data:
deleteData();
break;
case R.id.bt_query_data:
queryData();
break;
}
}
private void queryData() {
SQLiteDatabase db = myDatabaseHelper.getWritableDatabase();
Cursor cursor = db.query("Book" , null , null , null , null , null , null);
while (cursor.moveToNext()){
Log.d("MainActivity" , cursor.getString(cursor.getColumnIndex("name")));
}
cursor.close();
}
private void deleteData() {
SQLiteDatabase db = myDatabaseHelper.getWritableDatabase();
db.delete("Book", "author = ?", new String[]{"鲁迅"});
Toast.makeText(this, "删除成功", Toast.LENGTH_SHORT).show();
}
private void updateData() {
SQLiteDatabase db = myDatabaseHelper.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("name", "The Da Vinci Code");
db.update("Book", contentValues, "name = ?", new String[]{"达芬奇密码"});
Toast.makeText(this, "更新成功", Toast.LENGTH_SHORT).show();
}
private void insertData() {
SQLiteDatabase db = myDatabaseHelper.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("name", "达芬奇密码");
contentValues.put("pages", "454");
contentValues.put("author", "丹布朗");
contentValues.put("price", "50");
db.insert("Book", null, contentValues);
contentValues.clear();
contentValues.put("name", "百草书屋");
contentValues.put("pages", "300");
contentValues.put("author", "鲁迅");
contentValues.put("price", "100");
db.insert("Book", null, contentValues);
contentValues.clear();
Toast.makeText(this, "添加成功", Toast.LENGTH_SHORT).show();
}
}
我们先通过上面运行起来,创建数据库,然后添加一些数据上去。(这上面其实是《第一行代码》里讲数据库的内容,为了方便,作者在讲ContentProvider的时候就在这基础上进行修改)
接下来才是跟我们主题相关的内容:
新建一个类继承自ContentProvider:
public class DatabaseProvider extends ContentProvider {
public static final int BOOK_DIR = 0;
public static final int BOOK_ITEM = 1;
public static final int CATEGORY_DIR = 2;
public static final int CATEGORY_ITEM = 3;
public static final String AUTHORITY = "com.example.jdnew.databasetest.provider";
private static UriMatcher uriMatcher;
private MyDatabaseHelper databaseHelper;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY , "book" , BOOK_DIR);
uriMatcher.addURI(AUTHORITY , "book/#" , BOOK_ITEM);
uriMatcher.addURI(AUTHORITY , "category" , CATEGORY_DIR);
uriMatcher.addURI(AUTHORITY , "category/#" , CATEGORY_ITEM);
}
@Override
public boolean onCreate() {
databaseHelper = new MyDatabaseHelper(getContext() , "BookStore.db" , null , 2);
return true;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection,
@Nullable String selection, @Nullable String[] selectionArgs,
@Nullable String sortOrder) {
SQLiteDatabase sqLiteDatabase = databaseHelper.getReadableDatabase();
Cursor cursor = null;
switch (uriMatcher.match(uri)){
case BOOK_DIR:
cursor = sqLiteDatabase.query("Book" , projection , selection ,
selectionArgs , null , null ,sortOrder);
break;
case BOOK_ITEM:
String bookId = uri.getPathSegments().get(1);
cursor = sqLiteDatabase.query("Book" , projection , "id = ?" ,
new String[]{bookId} , null , null , sortOrder);
break;
case CATEGORY_DIR:
cursor = sqLiteDatabase.query("Category" , projection , selection ,
selectionArgs , null , null , sortOrder);
break;
case CATEGORY_ITEM:
String categoryId = uri.getPathSegments().get(1);
cursor = sqLiteDatabase.query("Category" , projection , "id = ?" ,
new String[]{categoryId} , null , null , sortOrder);
break;
}
return cursor;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
switch (uriMatcher.match(uri)){
case BOOK_DIR:
return "vnd.android.cursor.dir/vnd.com.example.jdnew.databasetest.provider.book";
case BOOK_ITEM:
return "vnd.android.cursor.item/vnd.com.example.jdnew.databasetest.provider.book";
case CATEGORY_DIR:
return "vnd.android.cursor.dir/vnd.com.example.jdnew.databasetest.provider.category";
case CATEGORY_ITEM:
return "vnd.android.cursor.dir/vnd.com.example.jdnew.databasetest.provider.category";
}
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
SQLiteDatabase sqLiteDatabase = databaseHelper.getWritableDatabase();
Uri uriReturn = null;
switch (uriMatcher.match(uri)){
case BOOK_DIR:
case BOOK_ITEM:
long newBookId = sqLiteDatabase.insert("Book" , null , contentValues);
uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId);
break;
case CATEGORY_DIR:
case CATEGORY_ITEM:
long newCategoryId = sqLiteDatabase.insert("Category" , null , contentValues);
uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId);
break;
}
return uriReturn;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection,
@Nullable String[] selectionArgs) {
SQLiteDatabase sqLiteDatabase = databaseHelper.getWritableDatabase();
int deletedRows = 0;
switch (uriMatcher.match(uri)){
case BOOK_DIR:
deletedRows = sqLiteDatabase.delete("Book" , selection , selectionArgs);
break;
case BOOK_ITEM:
String bookId = uri.getPathSegments().get(1);
deletedRows = sqLiteDatabase.delete("Book" , "id = ?" , new String[]{bookId});
break;
case CATEGORY_DIR:
deletedRows = sqLiteDatabase.delete("Category" , selection , selectionArgs);
break;
case CATEGORY_ITEM:
String categoryId = uri.getPathSegments().get(1);
deletedRows = sqLiteDatabase.delete("Category" , "id = ?" ,
new String[]{categoryId});
break;
}
return deletedRows;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues contentValues,
@Nullable String selection, @Nullable String[] selectionArgs) {
SQLiteDatabase sqLiteDatabase = databaseHelper.getWritableDatabase();
int updatedRows = 0;
switch (uriMatcher.match(uri)){
case BOOK_DIR:
updatedRows = sqLiteDatabase.update("Book" , contentValues , selection ,
selectionArgs);
break;
case BOOK_ITEM:
String bookId = uri.getPathSegments().get(1);
updatedRows = sqLiteDatabase.update("Book" , contentValues , "id = ?" ,
new String[]{bookId});
break;
case CATEGORY_DIR:
updatedRows = sqLiteDatabase.update("Category" , contentValues , selection ,
selectionArgs);
break;
case CATEGORY_ITEM:
String categoryId = uri.getPathSegments().get(1);
updatedRows = sqLiteDatabase.update("Category" , contentValues , "id = ?" ,
new String[]{categoryId});
break;
}
return updatedRows;
}
}
onCreate()
一般在这里做数据库的创建和升级的操作等,只有当有ContentResolver来访问这里的数据的时候,内容提供器才会被初始化。(注:这是个返回boolean值的方法,因此创建成功后要返回true)
query(@NonNull Uri uri, @Nullable String[] projection,
@Nullable String selection, @Nullable String[] selectionArgs,
@Nullable String sortOrder)
使用uri来确定查询的表,projection表示哪些列,selection和selectionArgs用来约束查询哪些行,sortOrder表示排序。(注:这里将查询的结果以curosr返回)
insert(@NonNull Uri uri, @Nullable ContentValues contentValues)
uri表示插入的表,contentValue则是插入的数据。(注:返回用于标识插入该条数据的uri)
delete(@NonNull Uri uri, @Nullable String selection,
@Nullable String[] selectionArgs)
uri表示删除的表,selection和selectionArgs用来约束删除哪些行。(注,返回的是删除的行数int)
update(@NonNull Uri uri, @Nullable ContentValues contentValues,
@Nullable String selection, @Nullable String[] selectionArgs)
uri代表更新的表,contentValue用于存储更新的数据,selection和selectionArgs用来约束更新哪些行。(注:同样返回的是受影响的行数int)
getType(@NonNull Uri uri)
根据传入的内容URI来返回相应的MIME类型。(注:返回的是MIME类型的字符串String)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(插入:
那么什么是MIME类型呢?
MIME全程是Multipurpose Internet Mail Extensions,多用途互联网邮件扩展。通过查阅资料后我所了解到的是这种类型是起初用在浏览器里的,因为我们的浏览器要处理很多种数据,文字,音频,图像,视频等等,那么就需要这么一种格式规范类型来表示这么多不同的数据,让浏览器能更好地识别。)
那么在android里的ContentProvider里,这里也有自己的一套格式规范,它对这个MIME类型字符串的构成由三部分组成:
1.必须以vnd开头
2.如果URI以路径结尾,那么后接android.cursor.dir/ ; 如果以id结尾,那么后接android.cursor.item/
3.最后接上vnd . <authority> . <path>
回想一下上一篇所讲的,我们要去解析的时候需要一个uri,这个uri是由权限和路径组成的,也就是上方第三条的authority和path这两个。
权限默认是包名,路径就是我们的表名,或是表名下的某条数据,就是这样:com.example.app.provider + table1 = com.example.app.provider/table1。然后再加上规范的写法,那么它就是content://com.example.app.provider/table1。
ok,那我们现在撇开规范,只要权限和路径,以上方这条uri:com.example.app.provider/table1为例,它得出来的MIME类型字符串为:
vnd . android.cursor.dir/ vnd . com.example.app.provider . table1
如果在com.example.app.provider/table1后面加上个id:com.example.app.provider/table1/1
那么MIME类型字符串就变成vnd . android.cursor.item/ vnd . com.example.app.provider . table1
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
哦,再说下UriMatcher,这个类是用来匹配我们的Uri的,像一开始我们对它进行了初始化,然后把我们要的Uri给添加进去:
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY , "book" , BOOK_DIR);
uriMatcher.addURI(AUTHORITY , "book/#" , BOOK_ITEM);
uriMatcher.addURI(AUTHORITY , "category" , CATEGORY_DIR);
uriMatcher.addURI(AUTHORITY , "category/#" , CATEGORY_ITEM);
switch (uriMatcher.match(uri)){
case BOOK_DIR:
updatedRows = sqLiteDatabase.update("Book" , contentValues , selection ,
selectionArgs);
break;
case BOOK_ITEM:
String bookId = uri.getPathSegments().get(1);
updatedRows = sqLiteDatabase.update("Book" , contentValues , "id = ?" ,
new String[]{bookId});
break;
case CATEGORY_DIR:
updatedRows = sqLiteDatabase.update("Category" , contentValues , selection ,
selectionArgs);
break;
case CATEGORY_ITEM:
String categoryId = uri.getPathSegments().get(1);
updatedRows = sqLiteDatabase.update("Category" , contentValues , "id = ?" ,
new String[]{categoryId});
break;
}
然后最后的一步就是再Manifest文件里进行注册:
<provider
android:authorities="com.example.jdnew.databasetest.provider"
android:name="com.example.jdnew.databasetest.DatabaseProvider"
android:exported="true"/>
authorities就是我们一直在说的权限,然后name就是这个类的全名,然后exported设为true,表示可以被其它应用访问。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
那么上方的那个项目我们已经准备好了内容提供了,接下来就来试试看,我们的另外一个app是否能够去获取到上面这个app里的内容:
public class ProviderTestActivity extends AppCompatActivity implements View.OnClickListener {
private Button bt_insert_data;
private Button bt_update_data;
private Button bt_delete_data;
private Button bt_query_data;
private String newId;
private final String TAG = "ProviderTestActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_provider_test);
initView();
}
private void initView() {
bt_insert_data = (Button) findViewById(R.id.bt_insert_data);
bt_update_data = (Button) findViewById(R.id.bt_update_data);
bt_delete_data = (Button) findViewById(R.id.bt_delete_data);
bt_query_data = (Button) findViewById(R.id.bt_query_data);
bt_insert_data.setOnClickListener(this);
bt_update_data.setOnClickListener(this);
bt_delete_data.setOnClickListener(this);
bt_query_data.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_insert_data:
insertData();
break;
case R.id.bt_update_data:
updateData();
break;
case R.id.bt_delete_data:
deleteData();
break;
case R.id.bt_query_data:
queryData();
break;
}
}
private void queryData() {
Uri uri = Uri.parse("content://com.example.jdnew.databasetest.provider/book");
Cursor cursor = getContentResolver().query(uri , null , null ,null ,null);
if (cursor!=null) {
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
double price = cursor.getDouble(cursor.getColumnIndex("price"));
Log.d(TAG , "name is" + name);
Log.d(TAG , "author is " + author);
Log.d(TAG , "pages are " + pages);
Log.d(TAG , "price is " + price);
}
cursor.close();
}
}
private void deleteData() {
Uri uri = Uri.parse("content://com.example.jdnew.databasetest.provider/book/" + newId);
getContentResolver().delete(uri , null , null);
}
private void updateData() {
Uri uri = Uri.parse("content://com.example.jdnew.databasetest.provider/book/" + newId);
ContentValues contentValues = new ContentValues();
contentValues.put("name" , "A Storm of Swords");
contentValues.put("pages", 1216);
contentValues.put("price" , 25.2);
getContentResolver().update(uri , contentValues , null , null);
}
private void insertData() {
Uri uri = Uri.parse("content://com.example.jdnew.databasetest.provider/book");
ContentValues contentValues = new ContentValues();
contentValues.put("name", "百年孤独");
contentValues.put("author", "马尔克斯");
contentValues.put("pages", 300);
contentValues.put("price", 22.5);
Uri newUri = getContentResolver().insert(uri, contentValues);
newId = newUri.getPathSegments().get(1);
}
}