前言
ContentProvider作为Android中四大组件之一,它的中文意思是内容提供者,主要是用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另外一个程序中的数据,同时还能保证被访数据的安全性。是Android提供给上层的一个组件,主要用于实现数据访问的统一管理和数据共享。这里的数据管理是通过定义统一的访问接口来完成,如增删改查。同时,它采用了类似Internet的URL机制,将数据以URI的形式来标识,这样其他App就可以采用一套标准的URI规范来访问同一处数据,而不用关心具体的实现细节。比如我们的APP去访问通讯录,日历,短信等。(结合大佬们的博客总结的,如有侵权,麻烦联系我删除此文章)
基本用法
1、ContentProvider提供了一套通用的数据访问接口,我们只需要继承它,然后实现它的抽象方法。
public class ContactProvider extends ContentProvider {
//做一些初始化的操作
@Override
public boolean onCreate() {
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
return null;
}
//处理请求的Uri
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
}
这些接口貌似跟数据库的访问接口类似。没错,ContentProvider就是专门来管理数据库中的数据的。
2、每个想访问内容提供者的应用程序都需要依靠这个ContentResolver类,可以通过getContentResolver()方法获取到它的实例,它提供了一系列的方法用于对数据进行CRUD操作,其中,insert()方法用于添加数据,Update()方法用于更新数据,delete()用于删除数据,query()方法用于查询数据。ContentProvider就好比一个server,其他的App在访问这个ContentProvider的时候都必须先获得一个Server的Client才行,这里的ContentResolver就是Android提供给开发者使用来得到一个ContentProvider Client的管理工具类。
注意的是:ContentResolver中的CRUD操作方法都不是接收表名,而是使用一个Uri参数代替,这个参数被称为内容URI,它由两部分组成:authority和path。Authority是用于对不同的应用程序做区分的。Path是用于对同一应用程序中不同的两张表。如:content://com.example.app.privoder/table1。
3、另外需要操作安卓内部其他应用数据库的话,我们还需要去实现SQLiteOpenHelper
public class Helper extends SQLiteOpenHelper {
public Helper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//数据库升级时调用
}
}
实例一:获取联系人
第一步:新建一个类表示我们要得到的联系人对象
public class ContactInfo {
private String name;
private String phone;
private String email;
private String qq;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getQq() {
return qq;
}
public void setQq(String qq) {
this.qq = qq;
}
@Override
public String toString() {
return "ContactInfo [name=" + name + ", phone=" + phone + ", email="
+ email + ", qq=" + qq + "]";
}
}
第二步:新建一个获取联系人列表的方法类
public class ContactUtils {
public static ArrayList<ContactInfo> getContact(Context context) {
ArrayList<ContactInfo> list = new ArrayList<>();
ContentResolver resolver = context.getContentResolver();
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri datauri = Uri.parse("content://com.android.contacts/data");
Cursor cursor = resolver.query(uri, new String[] { "contact_id" },
null, null, null);
while (cursor.moveToNext()) {
String id = cursor.getString(0);
System.out.println("00"+id);
if (id != null) {
ContactInfo info = new ContactInfo();
Cursor datacursor = resolver.query(datauri, new String[] {
"data1", "mimetype" }, "raw_contact_id = ?",
new String[] { id }, null);
while (datacursor.moveToNext()) {
String data1 = datacursor.getString(0);
String mimetype = datacursor.getString(1);
if ("vnd.android.cursor.item/name".equals(mimetype)) {
info.setName(data1);
} else if ("vnd.android.cursor.item/im".equals(mimetype)) {
info.setQq(data1);
} else if ("vnd.android.cursor.item/email_v2"
.equals(mimetype)) {
info.setEmail(data1);
} else if ("vnd.android.cursor.item/phone_v2"
.equals(mimetype)) {
info.setPhone(data1);
}
}
datacursor.close();
list.add(info);
}
}
cursor.close();
return list;
}
}
第三步:运行查看结果
ArrayList<ContactInfo> contactlist = ContactUtils.getContact(this);
LogUtil.log("info" + contactlist.size());
2019-06-23 18:43:13.248 21155-21155/sayhallo.cn.ilikeandroid E/LOG_: info162
实例二:操作其他APP的数据库
第一步:新建一个类继承SQLiteOpenHelper提供共享数据库
public class Helper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "test.db";
public static final int DATABASE_VERSION = 1;
public static final String SQL_CREATE_TABLE = "create table account (_id integer primary key autoincrement,name varchar(20),number varchar(20))";
public Helper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
第二步:新建一个类继承ContentProvider,实现接口提供调用者使用
public class ContactProvider extends ContentProvider {
private static final int SUCCESS = 1;
/** 判断Uri规则 */
static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
mUriMatcher.addURI("com.exmple.text", "account", SUCCESS); //uri规则可自己定义,但一定和清单文件一直
}
@Override
public boolean onCreate() {
return false;
}
/** 增删改查为空实现 */
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
int code = mUriMatcher.match(uri); // 判断Uri是否合法
if (code == SUCCESS) {
LogUtil.log("查询数据");
Helper helper = new Helper(getContext());
SQLiteDatabase db = helper.getReadableDatabase();
return db.query("account", projection, selection, selectionArgs,
null, null, sortOrder);
} else {
throw new IllegalArgumentException("路径不正确");
}
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
int code = mUriMatcher.match(uri);
if (code == SUCCESS) {
LogUtil.log("添加数据");
Helper helper = new Helper(getContext());
SQLiteDatabase db = helper.getWritableDatabase();
db.insert("account", null, values);
getContext().getContentResolver().notifyChange(uri, null); // 内容观察者检测数据库是否更改
} else {
throw new IllegalArgumentException("路径不正确");
}
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int code = mUriMatcher.match(uri);
if (code == SUCCESS) {
LogUtil.log("删除数据");
Helper helper = new Helper(getContext());
SQLiteDatabase db = helper.getWritableDatabase();
db.delete("account", selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null); // 内容观察者检测数据库是否更改
} else {
throw new IllegalArgumentException("路径不正确");
}
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int code = mUriMatcher.match(uri);
if (code == SUCCESS) {
LogUtil.log("更新数据");
Helper helper = new Helper(getContext());
SQLiteDatabase db = helper.getWritableDatabase();
db.update("account", values, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null); // 内容观察者检测数据库是否更改
} else {
throw new IllegalArgumentException("路径不正确");
}
return 0;
}
}
配置文件中添加provider节点:
<!-- 注册内容提供者数据 -->
<provider
android:name="com.example.provider.BackDoor"
android:authorities="com.exmple.text" >
</provider>
第三步:其他APP调用此接口
/**
* 利用后门程序 添加一条数据
*/
public void insert(View view) {
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.exmple.text/account");
ContentValues values = new ContentValues();
values.put("name", "zhangsan");
values.put("number", 10000);
resolver.insert(uri, values);
}
/**
* 利用后门程序 删除一条数据
*/
public void delete(View view) {
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.exmple.text/account");
resolver.delete(uri, "name=?", new String[] { "zhangsan" });
}
/**
* 利用后门程序 修改数据
*/
public void update(View view) {
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.exmple.text/account");
ContentValues values = new ContentValues();
values.put("number", 20000);
resolver.update(uri, values, "name=?", new String[] { "zhangsan" });
}
/**
* 利用后门程序 查询数据
*/
public void query(View view) {
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.exmple.text/account");
Cursor cursor = resolver.query(uri, new String[] { "name", "number" },
null, null, null);
while (cursor.moveToNext()) {
String name = cursor.getString(0);
float number = cursor.getFloat(1);
Log.e("LOG_","name:" + name + "----" + "number:" + number);
}
cursor.close();
}
第四步:运行查看结果
2019-06-23 19:11:26.080 25084-25099/sayhallo.cn.ilikeandroid E/LOG_: 添加数据
2019-06-23 19:11:27.437 25084-25099/sayhallo.cn.ilikeandroid E/LOG_: 添加数据
2019-06-23 19:11:29.301 25084-25099/sayhallo.cn.ilikeandroid E/LOG_: 更新数据
2019-06-23 19:11:36.005 25084-25099/sayhallo.cn.ilikeandroid E/LOG_: 查询数据
2019-06-23 19:11:36.019 25495-25495/sayhallo.cn.server E/LOG_: name:zhangsan----number:20000.0
2019-06-23 19:11:36.020 25495-25495/sayhallo.cn.server E/LOG_: name:zhangsan----number:20000.0
2019-06-23 19:11:41.251 25084-25099/sayhallo.cn.ilikeandroid E/LOG_: 查询数据
2019-06-23 19:11:41.269 25495-25495/sayhallo.cn.server E/LOG_: name:zhangsan----number:20000.0
2019-06-23 19:11:41.270 25495-25495/sayhallo.cn.server E/LOG_: name:zhangsan----number:20000.0
2019-06-23 19:11:46.363 25084-25099/sayhallo.cn.ilikeandroid E/LOG_: 查询数据
2019-06-23 19:11:46.385 25495-25495/sayhallo.cn.server E/LOG_: name:zhangsan----number:20000.0
2019-06-23 19:11:46.386 25495-25495/sayhallo.cn.server E/LOG_: name:zhangsan----number:20000.0
2019-06-23 19:11:52.202 25084-25099/sayhallo.cn.ilikeandroid E/LOG_: 添加数据
2019-06-23 19:11:54.213 25084-25099/sayhallo.cn.ilikeandroid E/LOG_: 查询数据
2019-06-23 19:11:54.238 25495-25495/sayhallo.cn.server E/LOG_: name:zhangsan----number:20000.0
2019-06-23 19:11:54.240 25495-25495/sayhallo.cn.server E/LOG_: name:zhangsan----number:20000.0
2019-06-23 19:11:54.240 25495-25495/sayhallo.cn.server E/LOG_: name:zhangsan----number:10000.0
2019-06-23 19:11:55.954 25084-25099/sayhallo.cn.ilikeandroid E/LOG_: 添加数据
2019-06-23 19:11:57.383 25084-25099/sayhallo.cn.ilikeandroid E/LOG_: 查询数据
2019-06-23 19:11:57.412 25495-25495/sayhallo.cn.server E/LOG_: name:zhangsan----number:20000.0
2019-06-23 19:11:57.413 25495-25495/sayhallo.cn.server E/LOG_: name:zhangsan----number:20000.0
2019-06-23 19:11:57.414 25495-25495/sayhallo.cn.server E/LOG_: name:zhangsan----number:10000.0
2019-06-23 19:11:57.415 25495-25495/sayhallo.cn.server E/LOG_: name:zhangsan----number:10000.0
网友评论