Android应用四大组件之一
为了在应用程序之间交换数据,Android提供了ContentProvider,它是不同应用程序之间进行数据交换的标准API,ContentProvider以某种Uri的形式对外提供数据,让其他应用程序使用ContentResolver根据Uri去访问操作数据
那么如何完整开发一个ContentProvider呢?
- 首先定义自己的ContentProvider类,该类继承Android的ContentProvider基类
- 然后在项目的AndroidMainfest.xml中注册ContentProvider,同时还需为他绑定一个Uri
<!--下面配置中name属性相当于ContentProvider类
authorities相当于为该类ContentProvider指明域名
exported为true时表明可以共享数据-->
<provider android:exported="false"
android:authorities="com.provider.Simple"
android:name="SimpleProvider">
<grant-uri-permission android:pathPattern=".*"/>
</provider>
注册了SimpleProvider之后,就要知道SimpleProvider如何暴露它的数据。我们知道数据的操作无非就是增删改查等几个操作,因此SimpleProvider除了继承之外,还应该提供以下的的方法
- public boolean onCreate() :在创建ContentProvider时调用
,当其他程序第一次调用时就会被创建出来 - public Cursor query(Uri, String[], String, String[], String) 用于查询指定Uri的ContentProvider,返回一个Cursor
- public Uri insert(Uri, ContentValues) 用于添加数据到指定Uri的ContentProvider中
- public int update(Uri, ContentValues, String, String[]) 用于更新指定Uri的ContentProvider中的数据
- public int delete(Uri, String, String[]) 用于从指定Uri的ContentProvider中删除数据
public String getType(Uri) 用于返回指定的Uri中的数据E类型
- MIME类型字符串以vnd.android.cursor.dir/开头时该Uri的数据可能包含多条
- 以vnd.android.cursor.item/开头时,处理的数据为一条
- vnd.< name >.< type >中的name具有表中唯一性
这些操作与数据库的操作基本上完全一样,在此不详细说,需要特殊说明的地方是URI:
在URI的D部分可能包含一个_ID ,这个应该出现在SQL语句中的,可以以种特殊的方式出现,这就要求我们在提供数据的时候,需要来额外关注这个特殊的信息。Android SDK推荐的方法是:在提供数据表字段中包含一个ID,在创建表时INTEGER PRIMARY KEY AUTOINCREMENID字段
ContentProvider 是如何组织数据的?
组织数据主要包括:存储数据,读取数据,以数据库的方式暴露数据。数据的存储需要根据设计的需求,选择合适的存储结构,首选数据库,当然也可以选择本地其他文件,甚至可以是网络上的数据。数据的读取,以数据库的方式暴露数据这就要求,无论数据是如何存储的,数据最后必须以数据的方式访问。
Android是如何实现应用程序之间数据共享的?我们以前谈到外界的程序可以通过ContentResolver接口访问ContentProvider提供的数据,今天我们来谈下如何创建自己的ContentProvider来实现应用程序之间的数据共享
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方法来实现。
ContentProvider 什么是URI?
content ://com.android.provider/student
将其分为3个部分:
- “conte://”:标准前缀,用来说明一个Content Provider控制这些数据,无的
- com.android.provider:URI的标识,它定义了是哪个Content Provid提供这些数 据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的类名。是contentProvider的authorities,系统根据该部分找到操作哪个contentProvider称 ;”content://com.android.calendar” (系统日历的URI)
- student:路径,URI下的某一个Item,就像网站一样,主网页下包含很多小网页。这里通俗的讲就是你要操作的数据库中表的名字,或者你也可以自己定义,记得在使用的时候保致就ok了
- “content://com.android.provider/student/#”
- #表示数任意数字的数字字符组成 - “content://com.android.provider/*”
- *来匹配任意文本
- “content://com.android.provider/student/#”
UriMatcher:用于匹配Uri,它的用法如下:
- 首先把你需要匹配Uri路径全部给注册上。
- 常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。
UriMautcher riMatcher = new UriMatcher(UriMatcher.NO_MATCH);
- 如果match()方法匹content://com.android.calendar/calendars路径,返回匹配O_MATCH);
uriMatcher.addURI(“content://com.android.calendar”, “calendars”, 1);
- 添加需要匹配uri,如果匹配就会返回匹配码,如果match()方法匹配 content://com.android.calendar/calendars/23路径,返回匹配码为2 uriMatcher.addURIiMatcher.addURI
注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配,如果匹 配就返回匹配码,匹配码是调用 addURI()方法传入的第三个参数,假设匹配content://com. android.calendar/calendars路径,返回的匹配码为1。
ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
withAppendedId(uri, id)用于为路径加上ID部分
parseId(uri)方法用于从路径中获取ID部分
以下是一个例子的简单说明:
private static final String URI_AUTHORITY = "com.calendarwidget.provider";
public static final String URI_PATH2 = "RecordSet/#";//只是填充,没有作用
public static final Uri CONTENT_URI = Uri.parse("content://"
private static final UriMatcher sMatcher;
public static final int ALL_EVENT_RECORDS = 0;
sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sMatcher.addURI(URI_AUTHORITY, URI_PATH, ALL_EVENT_RECORDS);
sMatcher.addURI(URI_AUTHORITY, URI_PATH2, ALL_EVENT_RECORDS);
public boolean onCreate()
if (mContext == null)
mContext = getContext();
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
//匹配码
int match = sMatcher.match(uri);
switch (match)
case ALL_EVENT_RECORDS:
cur = loadAllCalendarEvent(this);
default:
break;
return cur;
private MatrixCursor loadAllCalendarEvent(CalendarProvider calendarProvider)
MatrixCursor mc = new MatrixCursor(CalendarConstants.PROJECTION);
calendarCursor = calendarProvider
.getContentResolver().query("content://com.android.calendar/calendars",
while (calendarCursor.moveToNext())
//TODO
.....
mc.addRow(rowObject);
} finally
calendarCursor.close();
@Override
public String getType(Uri uri)
}
@Override
public Uri insert(Uri uri, ContentValues values)
@Override
public int delete(Uri uri, String selection, String[] selectionArgs)
public int update(Uri uri, ContentValues values, String selection,
}
}
public class CalendarProvider extends ContentProvider
public static final String URI_PATH = "RecordSet"; //只是填充,没有作用
{
}
private Context mContext;
{
}
String[] selectionArgs, String sortOrder)
break;
}
{
Cursor calendarCursor = null;
.getContext()
null, null,
null, null); /
}
return mc;
}
{
return null;
return null;
{
}
@Override
String[] selectionArgs)
return 0;