Android学习笔记:ContentProvider
ContentProvider
一、内容提供器介绍
内容提供器(ContentProvider)主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性。
内容提供器可以选择只对哪一部分数据进行共享,从而保证我们程序中的隐私数据不会有泄漏的风险
二、内容提供器构成
1.使用方法
- 使用现有的内容提供器来读取和操作相应程序中的数据
- 创建自己的内容提供器给我们程序的数据提供外部访问接口
2.ContentResolver
程序通过ContentResolver类来访问ContentProvider*享的数据,通过Context中getContentResolver()方法来获取该类的实例
- insert() 用于添加数据
- update() 用于更新数据
- delete() 用于删除数据
- query() 用于查询数据
3.URI
- authority
用于对不同的应用程序作区分,一般为了避免冲突,都会采用程序包名的方式来进行命名 - path
用于对同一应用程序中不同的表作区分,通常添加到authority后面
内容URI标准格式写法"content://" + authority + path:
content://com.example.app.provider/table1
content://com.example.app.provider/table2/1
以路径结尾就表示期望访问表中所有数据,id结尾则表示访问表中拥有相应id的数据
有了URI后还需要将其解析为Uri对象
Uri uri = Uri.parse("content://com.example.app.provider/table1")
我们也可以用通配符来匹配内容URI
*:表示匹配任意长度的任意字符
#:表示匹配任意长度的数字
我们可以借助UriMatcher来匹配内容URI功能(映射)
public static final String AUTHORITY = "com.example.savetest.provider";
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;
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);
}
...
public Cursor query(Uri uri, ...) {
switch ((uriMatcher.match(uri))){
case BOOK_DIR:
// 查询Book表所有数据
break;
case BOOK_ITEM:
// 查询Book表单条数据
break;
case CATEGORY_DIR:
// 查询Category所有数据
break;
case CATEGORY_ITEM:
// 查询Category单条数据
break;
default:
break;
}
...
}
4.MIME格式
getType()方法用于获取Uri对象所对应的MIME类型,其中MIME格式有如下组成:
- 以vnd开头
- 如果URI以路径结尾,则接android.cursor.dir/ 如果以id结尾,则接 android.cursor.item/
- 最后接上vnd.< authority >.< path >
content://com.example.app.provider/table
对应MIME:vnd.android.cursor.dir/vnd.com.example.app.provider.table
5.ContentProvider
我们可以通过新建一个类去继承ContentProvider的方式来创建一个自己的内容提供器,我们需要重写以下6个方法
- onCreate()
初始化时调用,返回true表示初始化成功,返回false表示失败 - query()
查询数据,uri表示查询哪张表,projection表示查询哪些列,selection和selectionArgs用于约束查询哪些行,sortOrder用于对结果排序,查询结果存放在Cursor对象中返回 - insert()
添加数据,uri确定添加到哪张表,values用于保存待添加的数据。添加完成后,返回一个表示该数据的URI - update()
更新已有的数据。uri确定更新的表,values保存新数据,selection和selectionArgs用于约束更新哪些行,受影响的行数作为返回值返回 - delete()
删除数据。uri确定删除的表,selection和selectionArgs用于约束删除哪些行,被删除的行数作为返回值返回 - getType()
根据传输的内容URI来返回相应的MIME类型
三、具体实现
ContentProvider:
package com.example.savetest;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
public class MyContentProvider 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.savetest.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, "category", CATEGORY_DIR);
uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM);
}
public MyContentProvider() {
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = dbHelper.getReadableDatabase();
int deletedRows = 0;
switch ((uriMatcher.match(uri))){
case BOOK_DIR:
deletedRows = db.delete("Book", selection, selectionArgs);
break;
case BOOK_ITEM:
deletedRows = db.delete("Book", "id = ?", selectionArgs);
break;
case CATEGORY_DIR:
deletedRows = db.delete("Category", selection, selectionArgs);
break;
case CATEGORY_ITEM:
deletedRows = db.delete("Category", "id = ?", selectionArgs);
break;
default:
break;
}
return deletedRows;
}
@Override
public String getType(Uri uri) {
switch ((uriMatcher.match(uri))){
case BOOK_DIR:
return "vnd.android.cursor.dir/vnd.com.example.savetest.provider.Book";
case BOOK_ITEM:
return "vnd.android.cursor.item/vnd.com.example.savetest.provider.Book";
case CATEGORY_DIR:
return "vnd.android.cursor.dir/vnd.com.example.savetest.provider.Category";
case CATEGORY_ITEM:
return "vnd.android.cursor.item/vnd.com.example.savetest.provider.Category";
default:
break;
}
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
Uri uriReturn = null;
switch ((uriMatcher.match(uri))){
case BOOK_DIR:
case BOOK_ITEM:
long newBookId = db.insert("Book", null, values);
uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId);
break;
case CATEGORY_DIR:
case CATEGORY_ITEM:
long newCategoryId = db.insert("CategoryId", null, values);
uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newCategoryId);
break;
default:
break;
}
return uriReturn;
}
@Override
public boolean onCreate() {
dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 1);
return true;
}
@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:
cursor = db.query("Book", projection, "id = ?", selectionArgs, null, null, sortOrder);
break;
case CATEGORY_DIR:
cursor = db.query("Category", projection, selection, selectionArgs, null, null, sortOrder);
break;
case CATEGORY_ITEM:
cursor = db.query("Category", projection, "id = ?", selectionArgs, null, null, sortOrder);
break;
default:
break;
}
return cursor;
}
@Override
public int update(Uri uri, ContentValues values,
String selection, String[] selectionArgs) {
SQLiteDatabase db = dbHelper.getReadableDatabase();
int updateRows = 0;
switch ((uriMatcher.match(uri))){
case BOOK_DIR:
updateRows = db.update("Book", values, selection, selectionArgs);
break;
case BOOK_ITEM:
updateRows = db.update("Book", values, "id = ?", selectionArgs);
break;
case CATEGORY_DIR:
updateRows = db.update("Category", values, selection, selectionArgs);
break;
case CATEGORY_ITEM:
updateRows = db.update("Book", values, "id = ?", selectionArgs);
break;
default:
break;
}
return updateRows;
}
}
DatabaseHelper:
package com.example.savetest;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;
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);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
db.execSQL(CREATE_CATEGORY);
Toast.makeText(mContext, "创建数据库表", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
MainActivity:
package com.example.savetest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
inputText = (EditText) findViewById(R.id.input_text);
showText = (TextView) findViewById(R.id.show_text);
// 创建数据库表
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);
sqlSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLInsertData();
}
});
sqlLoad.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
SQLSelectData();
}
});
}
// 使用SQL添加数据
public void SQLInsertData(){
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", "The Da Vinci Code");
values.put("author", "Dan Brown");
values.put("pages", 454);
values.put("price", 16.96);
db.insert("Book", null, values);
values.clear();
values.put("name", "The Lost Symbol");
values.put("author", "Dan Brown");
values.put("pages", 510);
values.put("price", 19.95);
db.insert("Book", null, values);
}
// 使用SQL读取数据
public void SQLSelectData(){
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor cursor = db.query("Book", null, null, null, null, null, null);
Log.d(TAG, "SQLSelectData: ");
if (cursor.moveToFirst()){
do {
// 遍历Cursor对象,取出所有数据打印
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: " + name);
Log.d(TAG, "author: " + author);
Log.d(TAG, "pages: " + pages);
Log.d(TAG, "price: " + price);
} while(cursor.moveToNext());
}
cursor.close();
}
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.savetest">
<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=".MyContentProvider"
android:authorities="com.example.savetest.provider"
android:enabled="true"
android:exported="true"></provider>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
四、个人理解
- 将数据private化,让自己成为getter()、setter(),提供ContentResolver的CRUD方法给其他程序来读取数据
- 其他程序通过Uri访问数据库,本质是ContentResolver提供方法,然后通过ContentProvider去访问数据库
上一篇: Android自定义控件学习笔记1
下一篇: Android 图片圆角和布局圆角应用