1.内容提供者概述
1.1 内容提供者功能概述
**内容提供者(ContentProvider)**主要用于在不同的应用程序之间实现数据共享的功能。 为什么使用? 因为通过数据持久化, .db或者SP(SharedPreferences)中的数据仅限于被创建的应用所访问,无法做到应用程序间的数据交互和共享。内容提供者就相当于对外部提供了一个操作当前应用数据库表的API,通过UriMatcher匹配相应的uri,达到对数据库中不同表CRUD的操作。
1.2 内容提供者使用场景
ContentProvider的使用场景多用于:
- 微信/支付宝 读取手机的联系人/通讯录
- 比如今日头条需要访问淘宝的内容,根据淘宝的用户访问习惯来给使用今日头条的用户推荐定向广告
-比如 开发一个蓝牙电话,需要向手机的联系人这个应用拿到手机的所有联系人
2.自定义ContentProvider
2.1 自定义ContentProvider的步骤
需要知道,Android的四大组件都是需要在AndroidManifest.xml中注册的. 创建自定义ContentProvider时,可以借助AndroidStudio的new ->Other->ContentProvider. 在创建时,需要勾选权限:
Exported 属性 表示允许外部程序访问该应用的ContentProviderEnabled 属性 表示是否启用这个内容提供器 还有一个最关键的是 URI Authorities ,这是令牌,只有匹配上了,才有权限来操作数据库。外部应用如果想要操作当前app,必须通过设置uri,然后UserProvider类中的UriMathcer会匹配外部app传递过来的uri来查看是否有权限操作当前app中的数据。Authorities可以是多个,通过";"来进行分割。 在创建ContentProvider之后,该项目的AndroidManifest.xml中就会有如下的代码:
<provider
android:name=".MyContentProvider"
android:authorities="com.hfad.providertest.provider"
android:enabled="true"
android:exported="true"></provider>
自定义的ContentProvider继承自ContentProvider,ContentProvider类中有6个抽象方法,在使用子类继承他的时候,需要将这6个方法全部重写。
public class MyProvider 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;
}
@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;
}
}
这些方法的功能分别是: 1.onCreate() 初始化内容提供器的时候调用。通常会在这里完成对数据库的创建和升级等操作,返回true表示内容提供器初始化成功,返回false则表示失败。注意,只有当存在ContentResolver尝试访问我们程序中的数据时,内容提供器才会被初始化。
2.query() 从内容提供器中查询数据。使用uri参数来确定查询哪张表,projection参数用于确定查询哪些列,selection和selectionArgs参数用于约束查询哪些行,sortorder参数用于对结果进行排序,查询的结果存放在Cursor对象中返回。
3.insert() 向内容提供器中添加一条数据。使用uri 参数来确定要添加到的表,待添加的数据保存在values参数中。添加完成后,返回一个用于表示这条新记录的URI。
4.update() 更新内容提供器中已有的数据。使用uri参数来确定更新哪一张表中的数据,新数据保存在values参数中,selection和 selectionArgs参数用于约束更新哪些行,受影响的行数将作为返回值返回。
5.delete()
从内容提供器中删除数据。使用uri参数来确定删除哪一张表中的数据,selection 和selectionArgs参数用于约束删除哪些行,被删除的行数将作为返回值返回。
6.getType()
根据传入的内容URI来返回相应的 MIME类型。
可以看到,几乎每一个方法都会带有Uri这个参数,这个参数也正是调用方–内容解析者ContentResolver的增删改查方法时传递过来的。而现在,我们需要对传入的Uri参数进行解析,从中分析出 调用方 期望访问的表和数据。
ContentProvider的5个方法中的Uri参数,全是其他应用(调用方–内容解析者ContentResolver)请求获取某一信息时传递过来的。
2.2 自定义URI写法及使用
URI: 统一资源标识符(Uniform Resource Identifier), 它和URL(统一资源定位符)什么关系呢,其实URI和URL都可以标识web主机上的资源,但URL是一种具体的URI,它是URI的一个子集,它不仅唯一标识资源,而且还提供了定位该资源的信息。而URI是对资源的抽象,实际应用还是URI居多。
- 主题名(Schema):ContentProvider的URI前缀(Android指定)
- 授权信息(Authority):ContentProvider的唯一标识符
- 表名(Path):ContentProvider指向数据库中的某个表明
- 记录(ID):表中的某个记录(若无指定,则返回全部记录)
UriMatcher : 外部若想对当前应用进行访问,必须能够匹配UriMatcher中的URI。 主要涉及到两个主要方法:
-
UriMatcher.addURI(String authorities,String path,int code) authorities : 添加匹配规则,对应Manifest中的authorities path : 一般标识 表名 表示为table_name 或者table_name\id code :当URI被匹配之后会返回后面的Match Code -
UriMathcer.match(Uri uri):对第三方传递的uri进行匹配
2.3 调用方-ContentResovler请求数据共享
ContentResovler 内容解析者,通过它和内容提供者的对接,才可以去对内容提供者中的数据进行操纵。通过调用上下文对象中的方法getContentResolver( ) 获取ContentResovler 对象,里面提供对内容提供者中数据库操作的API。
ContentResovler 内容解析者 是其他的应用,而不是包含ContentProvider的原应用。
获取数据代码样例
ContentResolver contentResolver = getContentResolver();
Uri uri = Uri.parse("content://cn.wjx.contentprovider/user");
Cursor cursor = contentResolver.query(uri, null, null, null, null);
while (cursor.moveToNext()) {
String id = cursor.getString(0);
String username = cursor.getString(1);
String password = cursor.getString(3);
Log.d(TAG, "user-->id:" + id + " username:" + username + " password:" + password);
}
*插入数据代码样例
ContentResolver contentResolver = getContentResolver();
Uri uri = Uri.parse("content://cn.wjx.contentprovider/user");
ContentValues values = new ContentValues();
ContentValues cv = new ContentValues();
cv.put(FIELD_USERNAME, "track");
cv.put(FIELD_PASSWORD, "xcn");
cv.put(FIELD_SEX, "female");
cv.put(FIELD_AGE, 22);
Uri insert = contentResolver.insert(uri, cv);
Log.d(TAG, "uri:"+insert);
2.4 使用总结
我们当我们需要暴露数据给第三方使用时,就需要知道前面的内容提供者怎么写了。
如果是读取别人的内容提供者内容,就需要后面的知识了。
学习内容提供者的话,顺便也要把数据库的知识巩固一下。
内容提供者的使用场景比较少,能列举出来就那么几个了。我只有在蓝牙电话上使用过内容提供者,当然啦,在我们的平时开发中,如果做社交软件的话,也需要获取到用户的联系人列表
然后保存到后台去,向用户推荐对应的好友用户
3.应用
使用内容提供者的几个应用:
- 读取短信验证码 参考链接:https://blog.csdn.net/qq_42676548/article/details/115176324
- 获取联系人相应信息
- 获取日历事件,向日历中添加提醒事件
4 参考链接:
本文参考:
- https://www.sunofbeach.net/a/1247852001912500224
- https://www.sunofbeach.net/a/1186839898213076992
- 郭霖-第一行代码(第二版)
|