一 ContentProvider
- 内容提供者(ContentProvider)是Android系统四大组件之一,它是不同应用程序之间进行数据共享的标准API,通过ContentResolver类可以访问ContentProvider中共享的数据。
- ContentProvider的工作原理如下:
- A程序使用ContetntProvider暴露数据,才能被其他程序操作。B程序通过ContetnResolver操作A程序暴露出来的数据,A程序将操作的结果返回给ContentResoler,然后ContetnResolver再将操作的结果返回给B程序。
1.1 数据模型- ContentProvider 使用基于数据库模型的简单表格来提供需要共享的数据,在该表格中,每一表示一条记录,而每一列代表特定类型和含义的数据,并且其中每一条数据记录都包含一个名为“_ID”的字段类标识每条数据。
1.2 Uri(统一资源标识符)
- 统一资源标识符(Uniform Resource Identifier,或URI)是一个用于标识某一资源名称的字符串。 该标识允许用户对任何(包括本地和互联网)的资源通过特定的协议进行交互操作。
- ContentResolver提供一系列增删改查的方法对数据进行操作,并且这些方法以Uri的形式对外提供数据。
- Uri为内容提供者中的数据建立了唯一标识符。它主要由三部分组成,scheme、authorities和path。
1.3 创建内容提供者
内容提供者创建步骤:
- 在程序包名处右击选择【New】->【Other】->【Content Provider】选项
- 输入内容提供者的Class Name(类名称)和URI Authorities(唯一标识,通常使用包名)
- 点击【Finish】按钮创建完成
private class MyObserver extends ContentObserver{
public MyObserver(Handler handler) {
super(handler);
}
public void onChange(boolean selfChange) {
super.onChange(selfChange);
}
//还需要重写增删改查的方法
//...
}
1.4 清单文件
- 内容提供者创建完成后,Android Studio会自动在AndroidManifest.xml中对内容提供者进行注册。
<application ......>
<provider
android:name=".MyContentProvider"
android:authorities="cn.itcast.mycontentprovider"
android:enabled="true"
android:exported="true" >
</provider>
</application>
- provider中的android:name代表是继承于ContentProvider类的的全路径名称。
-
android:authorities
:标识MyContentProvider
提供的数据,该值可以是一个或者多个URI authority,authorities之间用分号隔开。 -
android:enabled
:标识MyContentProvider
提供的数据能否被系统实例化 -
android:exported
:用于指示该服务是否能被其他程序应用组件调用或跟他交互; 取值为(true | false),如果设置成true,则能够被调用或交互,否则不能;设置为false时,只有同一个应用程序的组件或带有相同用户ID的应用程序才能启动或绑定该服务。
1.5 访问其他程序的数据
- 在不同的应用程序之间交换数据时,应用程序会通过ContentProvider暴露自身数据,便通过ContentResolver对程序暴露的数据进行操作,因此 CntentProvider充当一个中介的角色。由于在使用ContentProvider暴露数据时,提供了相应的 Uri,因此在访问现有的CntentProvider时,要指定相应的 Uri,然后再通过ContentResolver对象来实现对数据的操作。
1.5.1 访问提供者【了解】
- 从Uri访问 ContentProvider 的常用模式是使用 CursorLoader 在后台运行异步查询。UI中的 Activity 或 Fragment 会调用查询的 CursorLoader,其转而使用 ContentResolver 获取 ContentProvider。如此一来,用户便可在查询运行时继续使用UI。
- ContentResolver对象在客户 app的进程中,ContentProvider对象在app中,它们之间自动处理IPC。ContentProvider也是数据存储同数据的外在表现的一个抽象层。
- 注意:为了存取provider,app通常在它的manifest文件中请求特定的权限。
- 例如,为了从User Dictionary Provider中得到一个单词表,你需要调用ContentResolver.query()。query()方法实际调用User Dictionary Provider中的ContentProvider.query(),如下:
// Queries the user dictionary and returns results
mCursor = getContentResolver().query(
UserDictionary.Words.CONTENT_URI, // The content URI of the words table
mProjection, // The columns to return for each row
mSelectionClause // Selection criteria
mSelectionArgs, // Selection criteria
mSortOrder); // The sort order for the returned rows
- 下表显示了query的参数同SQL SELECT语句的对应关系:
1.5.2 通过ContentProvider查询其他程序数据
- 步骤:
- 通过parse()方法解析Uri
- 通过query()方法查询数据
- 通过while()遍历查询到的数据
//获取相应操作的Uri,Uri.parse()方法是将字符串转化成Uri对象。
Uri uri = Uri.parse("content://cn.itcast.mycontentprovider/person");
//获取ContentResolver对象
ContentResolver resolver = context.getContentResolver();
//通过ContentResolver对象查询数据
Cursor cursor = resolver.query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder);
//通过while()循环将Cursor对象中的数据遍历出来
while (cursor.moveToNext()) {
String address = cursor.getString(0);
long date = cursor.getLong(1);
int type = cursor.getInt(2);
}
cursor.close();
1.5.3 query方法
ContentResolver的query方法的函数接口如下:
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal)
参数说明:
- uri:要查询的数据的地址。
- projection:要查询的列,即需要返回的数据的字段。
- selection:查询条件,即需要满足的约束条件。
- selectionArgs:查询条件的参数,用于替换selection中的占位符。
- sortOrder:查询结果的排序方式。
- cancellationSignal:用于取消查询的信号。
返回值:
- Cursor:查询结果的游标对象。
注意事项:
- 如果查询不需要使用selection和selectionArgs,可以将它们设置为null。
- 如果不需要排序,可以将sortOrder设置为null。
- 如果不需要取消查询,可以将cancellationSignal设置为null。
示例代码:
Uri uri = Uri.parse("content://com.example.provider/user");
String[] projection = {"name", "age"};
String selection = "age > ?";
String[] selectionArgs = {"18"};
String sortOrder = "name ASC";
CancellationSignal cancellationSignal = null;
Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal);
1.5.4 多学一招:UriMatcher类【了解】
- 初始化UriMatcher
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
- 将Uri注册到UriMatcher中
matcher.addURI("cn.itcast.contentprovider", "people", PEOPLE); matcher.addURI("cn.itcast.contentprovider", "person/#", PEOPLE_ID);
- 与已经注册的Uri进行匹配
Uri uri = Uri.parse("content://" + "cn.itcast.contentprovider" + "/people");
int match = matcher.match(uri);
switch (match){
case PEOPLE:
//匹配成功后做的相关操作
case PEOPLE_ID:
//匹配成功后做的相关操作
default:
return null;
}
二 ContentObserver
- 内容观察者(ContentObserver)用于观察指定Uri所代表的数据的变化,当ContentObserver观察到指定Uri代表的数据发生变化时,就会触发onChange()方法,此时在onChange()方法中使用ContentResovler可以查询到变化的数据。
- 要使用ContentObserver观察数据变化,就必须在ContentProvider中调用ContentResolver的notifyChange()方法。
- ContentObserver的工作原理如下:
- 使用contentObserver观察 A程序的数据时,首先要在 A程序的ContentProvider中调用ContentResolver的notifyChange()方法,调用此方法后,当 B操作程序作 A程序中的数据时, A程序会向消息中心发送数据变化的消息。此时C程序会观察到消息中心的数据有变化,会触发 ContentObserver的onChange()方法。
创建ContentObserver的具体步骤如下:
- 使用contentObserver观察 A程序的数据时,首先要在 A程序的ContentProvider中调用ContentResolver的notifyChange()方法,调用此方法后,当 B操作程序作 A程序中的数据时, A程序会向消息中心发送数据变化的消息。此时C程序会观察到消息中心的数据有变化,会触发 ContentObserver的onChange()方法。
2.1 创建ContentObserver
- 创建一个类继承自ContentObserver,并重写onChange方法。
public class MyContentObserver extends ContentObserver { //Handler对象是主线程中的Handler对象,也可以是其他线程中的Handler对象 public MyContentObserver(Handler handler) { super(handler); } //当MyContentObserver观察到Uri代表的数据发生变化时,程序回调用onChange()方法,并在该方法中处理相关的逻辑 @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); // 处理数据变化的逻辑 } }
- 注册内容观察者
ContentResolver resolver = getContentResolver(); Uri uri = Uri.parse("content://aaa.bbb.ccc"); resolver.registerContentObserver(uri, true, new MyContentObserver(new Handler());
参数说明:
- uri:要监听的数据的地址。
- notifyForDescendants:是否监听uri的所有子路径。
- 取消注册内容观察者
getContentResolver().unregisterContentObserver(contentObserver);
通过以上步骤,就可以创建并使用ContentObserver来监听数据的变化。
注意事项:
- ContentObserver只能监听ContentProvider中数据的变化,而不能监听其他的数据源。
- ContentObserver的onChange方法在主线程中执行,如果需要执行耗时操作,建议在onChange中开启新的线程来处理。
- ContentObserver的注册和取消注册应该在合适的时机进行,避免不必要的资源消耗。
-
下面是一个完整的示例代码,演示如何创建和使用ContentObserver来监听数据的变化:
public class MainActivity extends AppCompatActivity { private MyContentObserver contentObserver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 创建ContentObserver对象 contentObserver = new MyContentObserver(new Handler()); // 注册ContentObserver监听数据变化 Uri uri = Uri.parse("content://com.example.provider/user"); getContentResolver().registerContentObserver(uri, true, contentObserver); } @Override protected void onDestroy() { super.onDestroy(); // 取消注册ContentObserver getContentResolver().unregisterContentObserver(contentObserver); } private class MyContentObserver extends ContentObserver { public MyContentObserver(Handler handler) { super(handler); } @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); // 处理数据变化的逻辑 Log.d("ContentObserver", "Data changed: " + uri.toString()); // 可以在这里更新UI或执行其他操作 } } }
- 在上述示例中,在MainActivity的onCreate方法中创建了一个ContentObserver对象,并在onDestroy方法中取消注册。在MyContentObserver的onChange方法中,我们可以处理数据变化的逻辑,例如打印日志或更新UI。
2.2 补充:注册ContetnObserver的时机
- 通常是在Activity、Fragment或Service等组件中的某个方法中注册ContentObserver来监听数据的变化。具体来说,可以在以下方法中注册ContentObserver:
- 在Activity中,可以在onCreate方法中注册,然后在onDestroy方法中取消注册。
- 在Fragment中,可以在onCreateView方法中注册,然后在onDestroyView方法中取消注册。
- 在Service中,可以在onCreate方法中注册,然后在onDestroy方法中取消注册。
- 具体选择,取决于业务需求和组件的生命周期。
- 示例代码:
public class MainActivity extends AppCompatActivity {
private MyContentObserver contentObserver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 创建ContentObserver对象
contentObserver = new MyContentObserver(new Handler());
// 注册ContentObserver监听数据变化
Uri uri = Uri.parse("content://com.example.provider/user");
getContentResolver().registerContentObserver(uri, true, contentObserver);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 取消注册ContentObserver
getContentResolver().unregisterContentObserver(contentObserver);
}
private class MyContentObserver extends ContentObserver {
public MyContentObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
// 处理数据变化的逻辑
Log.d("ContentObserver", "Data changed: " + uri.toString());
// 可以在这里更新UI或执行其他操作
}
}
}
三 题目总结
- 简述内容提供者的工作原理
- 假设B程序需要操作A程序数据库中的数据,一般需要A程序使用ContentProvider
暴露数据,才能被其他程序操作。B程序通过ContentResolver操作A程序暴露出来的数据,而A程序会将操作结果返回给ContentResolver,然后ContentResolver再将操作结果返回给B程序。
- 假设B程序需要操作A程序数据库中的数据,一般需要A程序使用ContentProvider
- 简述内容观察者的工作原理
- 使用ContentObserver观察A程序的数据时,首先要在A程序的ContentProvider中调用ContentResolver的notifyChange()方法。调用此方法后,当B程序操作A程序中的数据时,A程序会向“消息中心”发送数据变化的消息,此时C程序会观察到“消息中心”的数据有变化,会触发ContentObserver的onChange()方法。
- 在ContentProvider中ContentUris的作用是提供增删改查的方法
- 在ContentProvider中,ContentUris类提供了一些方法,用于处理操作数据库中的数据的URI。这些方法可以帮助开发者在增删改查数据时,对URI进行解析和操作。
具体来说,ContentUris的作用如下:
- 解析URI:ContentUris类的parseId()方法可以从URI中解析出对应的记录的ID。这个方法通常在查询或删除单个记录时使用。例如,可以使用ContentUris.parseId(uri)方法从URI中解析出记录的ID。
- 构建URI:ContentUris类的withAppendedId()方法可以将ID添加到URI中,构建出一个新的URI。这个方法通常在插入或更新记录时使用。例如,可以使用ContentUris.withAppendedId(baseUri, id)方法将ID添加到baseUri中,构建出新的URI。
- 获取记录的URI:ContentUris类的withAppendedId()方法也可以用于获取指定记录的URI。这个方法通常在查询或删除单个记录时使用。例如,可以使用ContentUris.withAppendedId(baseUri, id)方法获取指定记录的URI。
通过使用ContentUris类的方法,开发者可以方便地解析和操作URI,从而实现对数据库中的数据进行增删改查的操作。
- 若要实现对系统联系人的增删改查,需要使用的系统ContentProvider的Uri为Contacts.Phones.CONTENT_URI
- 联系人信息内容提供者的主机名是com.android.contacts
- 联系人信息的内容提供者的主机名是
com.android.contacts
,它是Android系统中默认的联系人信息提供者。通过该内容提供者,应用程序可以访问和操作设备上的联系人信息。
- 联系人信息的内容提供者的主机名是
- 下面哪些功能需要用ContentProvider来实现()。
A、读取系统中的短信内容
B、建立一个数据库
C、开机后自动启动一个程序
D、播放一段音乐
-
解析:
-
A、读取系统中的短信内容:需要使用ContentProvider来实现。Android系统中的短信内容存储在短信提供者中,开发者需要通过ContentResolver来查询短信提供者,从而读取系统中的短信内容。
-
B、建立一个数据库:不需要使用ContentProvider来实现。建立数据库可以直接使用SQLiteOpenHelper或Room等数据库框架来创建和管理数据库。
-
C、开机后自动启动一个程序:不需要使用ContentProvider来实现。开机后自动启动一个程序可以通过BroadcastReceiver和BOOT_COMPLETED广播来实现。
-
D、播放一段音乐:不需要使用ContentProvider来实现。播放音乐可以使用MediaPlayer或其他音频播放框架来实现,不涉及ContentProvider的使用。文章来源:https://www.toymoban.com/news/detail-498536.html
-
因此,只有读取系统中的短信内容需要使用ContentProvider来实现。其他功能不需要使用ContentProvider。文章来源地址https://www.toymoban.com/news/detail-498536.html
-
- 短信的内容提供者是()
A、ContactProvider
B、MessageProvider
C、SmsProvider
D、TelephonyProvider - 在下列选项中,联系人信息内容提供者的主机名是()
A、contact
B、com.android.contacts
C、com.android.provider.contact
D、com.android.provider.contacts - 内容提供者主要功能是实现跨程序共享数据的功能
- provider中的android:name代表是继承于ContentProvider类的的全路径名称。
- 为了解析Uri对象,Android系统提供了一个辅助工具类UriMatcher用于匹配Uri。
- Android中通过ContentResover.query()查询短信数据库的时候,第一个Uri参数如何写 contentprovider
- 内容观察者是通过观察消息中心来观察数据库的变化
- 消息中心是用来观察指定Uri所代表的数据
- 利用内容解析者读取短信数据库内容时,短信数据库SmsInfo表主要用来存储短信信息
- resolver.registerContentObserver()方法用于注册内容观察者
- 创建UriMatcher对象时调用
UriMatcher(int code)
,参数通常使用UriMatcher.NO_MATCH
,表示路径不满足条件返回_-1 - 当ContentObserver观察到指定Uri代表的数据发生变化时,就会触发ContentObserver的**onChange()**方法。
- 内容提供者把私有的数据给暴露出来,我们通过ContentResolver来进行查询数据
- 在Android中,是通过ContentResolver读取联系人信息的。
- 注册provider时需要指定两个属性android.name和android:authorities
- 短信数据是存放在sms表中的
- Android中通过内容提供者来读取联系人信息,data表用来保存联系人信息的.
- Android中读取联系人信息 有三张关键的表1 data表用来存储联系人信息的表,2 raw_contacts 表用来存储一共有多少个联系人. 3 mimetype表用来区分联系人信息的表
- 在短信接收器案例中,注册短信内容观察者时,使用的到Uri是Content://sms/。
四 补充
- 请简要说明 ContentProvider 对外共享数据的好处。
- 通过 ContentProvider 共享数据统一数据访问方式,使用起来更规范,通过数据库存储并指定了 URI,只有通过特定 URI 才能访问数据,使数据更安全。
- 请简要说明 ContentProvider、ContentResolver 和 ContentObserver 之间的联系。
- ContentProvider 可以共享自己的数据给外部应用访问,要访问 ContentProvider 暴露的数据就要用到 ContentResolver。
- ContentObserver 就相当于中间人的角色,它可以事实监听ContentProvider 的 数 据 是 否 发 生 变 化 , 如 果 发 生 变 化 就 会 触 发 onChange() 方 法 ,Contentresolver 可以在 onChange()方法中查询的哪些数据发生了变化再对数据进行操作。
到了这里,关于探索安卓内容提供者:构建、访问和管理数据【复习】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!