在Android 应用程序之间数据共享—-ContentResolver中,已经说明了Android是如何实现应用程序之间数据共享的,并详细解析了如何获取其他应用程序共享的数据。ContentProviders存储和检索数据,通过它可以让所有的应用程序访问到,这也是应用程序之间唯一共享数据的方法。那么如何将应用程序的数据暴露出去?
通过以前文章的学习,知道ContentResolver是通过ContentProvider来获取其他与应用程序共享的数据,那么ContentResolver与ContentProvider的接口应该差不多的。
其中ContentProvider负责
组织应用程序的数据;
向其他应用程序提供数据;
ContentResolver则负责
获取ContentProvider提供的数据;
修改/添加/删除更新数据等;
ContentProvider 是如何向外界提供数据的?
Android提供了ContentProvider,一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据完全暴露出去,而且ContentProviders是以类似数据库中表的方式将数据暴露,也就是说ContentProvider就像一个“数据库”。那么外界获取其提供的数据,也就应该与从数据库中获取数据的操作基本一样,只不过是采用URI来表示外界需要访问的“数据库”。至于如何从URI中识别出外界需要的是哪个“数据库”,这就是Android底层需要做的事情了,不在此详细说。简要分析下ContentProvider向外界提供数据操作的接口:
query(Uri, String[], String, String[], String)
insert(Uri, ContentValues)
update(Uri, ContentValues, String, String[])
delete(Uri, String, String[])
这些操作与数据库的操作基本上完全一样,在此不详细说,具体的解析可以参考Android Sqlite解析篇中的详细说明。需要特殊说明的地方是URI:
在URI的D部分可能包含一个_ID ,这个应该出现在SQL语句中的,可以以种特殊的方式出现,这就要求我们在提供数据的时候,需要来额外关注这个特殊的信息。Android SDK推荐的方法是:在提供数据表字段中包含一个ID,在创建表时INTEGER PRIMARY KEY AUTOINCREMENT标识此ID字段。
ContentProvider 是如何组织数据的?
组织数据主要包括:存储数据,读取数据,以数据库的方式暴露数据。数据的存储需要根据设计的需求,选择合适的存储结构,首选数据库,当然也可以选择本地其他文件,甚至可以是网络上的数据。数据的读取,以数据库的方式暴露数据这就要求,无论数据是如何存储的,数据最后必须以数据的方式访问。
可能还有2个问题,是需要关注的。
ContentProvider是什么时候创建的,是谁创建的?访问某个应用程序共享的数据,是否需要启动这个应用程序?这个问题在Android SDK中没有明确说明,但是从数据共享的角度出发,ContentProvider应该是Android在系统启动时就创建了,否则就谈不上数据共享了。这就要求在AndroidManifest.XML中使用<provider>元素明确定义。
可能会有多个程序同时通过ContentResolver访问一个ContentProvider,会不会导致像数据库那样的“脏数据”?这个问题一方面需要数据库访问的同步,尤其是数据写入的同步,在AndroidManifest.XML中定义ContentProvider的时候,需要考虑是<provider>元素multiprocess属性的值;另外一方面Android在ContentResolver中提供了notifyChange()接口,在数据改变时会通知其他ContentObserver,这个地方应该使用了观察者模式,在ContentResolver中应该有一些类似register,unregister的接口。
Android是如何实现应用程序之间数据共享的?我们以前谈到外界的程序可以通过ContentResolver接口访问ContentProvider提供的数据,今天我们来谈下如何创建自己的ContentProvider来实现应用程序之间的数据共享。
一个应用程序可以创建自己的数据,这个数据对该应用程序来说是私有的,外界更本看不到,也不知道数据是如何 存储的,或者是使用数据库还是使用文件,还是通过网上获得,这些一切都不重要,重要的是外界可以通过这一套标准及统一的接口和这个程序里的数据打交道,例 如:添加(insert)、删除(delete)、查询(query)、修改(update)。
Android为我们提供了ContentProvider来实现数据的共享,一个程序如果想让别的程序可以操作自己的数据,就定义自己的 ContentProvider,然后在AndroidManifest.xml中注册,其他application可以通过获取 ContentResolver通过Uri来操作上一程序的数据。
Android中的电话本等数据就是通过ContentProvider实现数据共享的,系统中有很多已经存在的共享Uri。我们可以使用ContentResolver通过Uri来操作不同表的数据;如Contacts.People.CONTENT_URI。
查询Content Provider的方法有两个:ContentResolver的query() 和 Activity 对象的 managedQuery(),二者接收的参数均相同,返回的都是Cursor 对象,唯一不同的是 使用managedQuery 方法可以让Activity 来管理 Cursor 的生命周期。
被管理的Cursor 会在 Activity进入暂停状态的时候调用自己的 deactivate 方法自行卸载,而在Activity回到运行状态时会调用自己的requery 方法重新查询生成的Cursor对象。如果一个未被管理的Cursor对象想被Activity管理,可以调用Activity的 startManagingCursor方法来实现。
什么是URI?
将其分为A,B,C,D 4个部分:
A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;"content://"
B:URI的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它 必须是一个完整的、小写的 类名。这个标识在 元素的 authorities属性中说明:一般是定义该ContentProvider的包. 类的名称 ;"content://com.android.calendar" (系统日历的URI)
C:路径,URI下的某一个Item,就像网站一样,主网页下包含很多小网页。这里通俗的讲就是你要操作的数据库中表的名 字,或者你也可以自己定义,记得在使用的时候保持一致就ok了;"content://com.android.calendar/calendars"
D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部; "content://com.android.calendar/calendars/#" #表示数据id(#代表任意数字)
"content://com.android.calendar/calendars/*" *来匹配任意文本
UriMatcher:用于匹配Uri,它的用法如下:
1.首先把你需要匹配Uri路径全部给注册上。
1.常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。 UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
2.如果match()方法匹content://com.android.calendar/calendars路径,返回匹配码为1
uriMatcher.addURI(“content://com.android.calendar”, “calendars”, 1);
3.添加需要匹配uri,如果匹配就会返回匹配码 //如果match()方法匹配
content://com.android.calendar/calendars/23路径,返回匹配码为2
uriMatcher.addURI(“content://com.android.calendar”, “calendars/#”, 2);
2.注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配,如果匹
配就返回匹配码,匹配码是调用 addURI()方法传入的第三个参数,假设匹配
content://com.android.calendar/calendars路径,返回的匹配码为1。
ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
withAppendedId(uri, id)用于为路径加上ID部分
parseId(uri)方法用于从路径中获取ID部分
以下是一个例子的简单说明:
Xml代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1" android:versionName="1.0"
android:installLocation="internalOnly" package="com.calendarwidget">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<!-- 告诉系统,你的应用程序有provider组件 -->
<provider android:name=".CalendarProvider"
android:authorities="com.calendarwidget.provider"
/>
</application>
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
</manifest>
public class CalendarProvider extends ContentProvider
Java代码
{
private static final String URI_AUTHORITY = "com.calendarwidget.provider";
public static final String URI_PATH = "RecordSet"; //只是填充,没有作用
public static final String URI_PATH2 = "RecordSet/#";//只是填充,没有作用
public static final Uri CONTENT_URI = Uri.parse("content://"
+ URI_AUTHORITY + "/" + URI_PATH);
private static final UriMatcher sMatcher;
public static final int ALL_EVENT_RECORDS = 0;
static
{
sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sMatcher.addURI(URI_AUTHORITY, URI_PATH, ALL_EVENT_RECORDS);
sMatcher.addURI(URI_AUTHORITY, URI_PATH2, ALL_EVENT_RECORDS);
}
private Context mContext;
@Override
public boolean onCreate()
{
if (mContext == null)
{
mContext = getContext();
}
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder)
{
//匹配码
int match = sMatcher.match(uri);
Cursor cur = null;
switch (match)
{
case ALL_EVENT_RECORDS:
cur = loadAllCalendarEvent(this);
break;
default:
break;
}
return cur;
}
private MatrixCursor loadAllCalendarEvent(CalendarProvider calendarProvider)
{
MatrixCursor mc = new MatrixCursor(CalendarConstants.PROJECTION);
Cursor calendarCursor = null;
try
{
calendarCursor = calendarProvider
.getContext()
.getContentResolver().query("content://com.android.calendar/calendars",
null, null,
null, null); /
while (calendarCursor.moveToNext())
{
//TODO
.....
mc.addRow(rowObject);
}
return mc;
} finally
{
calendarCursor.close();
}
}
@Override
public String getType(Uri uri)
{
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values)
{
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs)
{
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs)
{
return 0;
}
}
关于getType使用提示:
<intent-filter android:label="@string/resolve_edit">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.EDIT" />
<action android:name="com.android.notepad.action.EDIT_NOTE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>
我們很容易看出action和category是很容易匹配的,而我們傳的Uri的數據怎麼匹配呢,這時系統就會去調用你定義的ContentProvider中的getType,取得相關的返回值來和上面的data串進行匹配,當然getType的返回結果你是需要自己去定義的。
但在程序中你也可以自己知道data的類型,就直接匹配了:intent.setType(type);
相关推荐
Android中ContentProvider和ContentResolver详解 ContentProvider是Android系统中的一种机制,它允许应用程序之间共享数据。它提供了一种标准化的方式来存储和管理数据,使得不同的应用程序可以访问和共享数据。...
《Android应用开发详解》是郭宏志先生撰写的一本深入探讨Android应用开发的专业书籍,它为初学者和有经验的开发者提供了丰富的知识和实践经验。这本书不仅涵盖了基础理论,还包含了实际项目的源码,使得读者能够通过...
本篇文章将深入解析Android中的联系人操作,主要基于提供的博文链接:[《Android 联系人详解》](https://wenzongliang.iteye.com/blog/2154645)。 ### 1. Android联系人API概述 Android提供了一个丰富的API,允许...
本章将深入讲解如何创建和使用ContentProvider,包括URI设计、CRUD操作的实现,以及如何通过ContentResolver进行数据查询和修改。 第17章:Android数据存储 此章涵盖了Android应用中的数据存储方法,包括Shared ...
《Android应用开发详解》 作者:郭宏志 编著 内容简介 本书分为三个部分,包括基础篇、技术篇和应用篇。由浅入深地讲述了Android应用开发的方方面面。 第一篇 基础篇 第1章 Android概述 Android概述,讲述了...
其他应用通过ContentResolver与Content Provider交互,通过Uri请求数据。 了解并熟练掌握四大组件的使用是Android开发的基础。开发者需要根据应用需求,合理设计组件之间的协作,保证程序的稳定性和性能。同时,...
本资源包“android应用开发详解 源码 全”提供了全面的Android应用开发源码,对于想要深入探索Android开发的程序员来说,无疑是一份宝贵的资料。 首先,我们需要了解Android应用的基本结构。一个标准的Android应用...
- `ContentResolver`和`Uri`配合使用可以处理媒体文件,如图片和音频。 5. **权限管理** - 自Android 6.0起,需要在运行时请求`WRITE_EXTERNAL_STORAGE`和`READ_EXTERNAL_STORAGE`权限,以访问外部存储。 - 使用...
Android提供了多种数据存储方式,包括使用SharedPreferences进行轻量级的数据存储,文件存储用于读写文件,SQLite数据库提供了一个轻量级的关系型数据库解决方案,而ContentProvider和ContentResolver则为不同应用...
"android应用开发详解_源码(6-9)"这个压缩包文件提供了书籍《Android应用开发详解》第六章到第九章的源码,对于那些正在深入学习Android编程的开发者来说,这是一个极其有价值的学习材料。 首先,我们要明白Android...
通过实现ContentProvider类并定义Uri规则,其他应用可以通过ContentResolver查询、插入、更新和删除数据。 以上就是Android常用组件的基本介绍,理解并熟练掌握这些组件,将有助于开发者构建高效、用户友好的...
"Android 内容提供器详解" Android 内容提供器是 Android 操作系统中的一种核心组件,用于管理和共享应用程序之间的数据。内容提供器允许不同的应用程序共享数据,提供了一个统一的接口来访问和修改数据。 ...
12. **SQLite数据库**:Android内置轻量级关系型数据库,用于存储应用数据,掌握SQL语句和ContentResolver的使用是必要的。 13. **权限管理**:AndroidManifest.xml文件中声明应用所需的权限,如读写文件、访问网络...
ContentProvider、ContentResolver 6.5 105 Intent 106 用Intent启动Activity,并在Activity之间传递数据 106 调用其他应用程序中的Activity(打电话、浏览网页、发Email等) 109 接收和发送广播 113 接收系统广播 113...
在Android开发领域,掌握核心技术与实例详解至关重要,尤其对于初学者和有经验的开发者来说,深入理解这些章节的内容能够极大地提升开发效率和产品质量。这里我们主要聚焦于"android核心技术与实例详解光盘源代码2...
【Android ContentProvider详解】 ContentProvider是Android系统提供的一种机制,使得不同应用程序之间可以安全地共享数据。通过ContentProvider,开发者可以将自己的数据集暴露出来,供其他应用查询、添加、删除和...
Android组件使用详解 Android作为一款开放源代码的移动操作系统,在全球范围内被广泛采用,其开发平台的核心在于组件化编程。组件化编程是指将程序拆分成多个独立、可重用的组件,使得开发者能够像搭建积木一样,...