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 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
{ 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);
?