作为ANDROIDL四大组件(Compenent:Activity, Service, BreadcaseReceiver,ContentProvider)之一的Content provider,为其它应用程序(也可以是提供该Content provider的应用程序)提供了一个接口一致数据储存模型。通过该接口,你可以方便地提取你想要的数据,修改或者是删除都会变得相当方便。依照 ANDROI组件模型的原理,把数据储存与数据显示分离天来,这不但提高了组件重用性,也同时提供更高的完全性(每一个Content Provider都有自己的许可属性)。作为数据储存的后端,你可以使用有Sqlite3保存数据,也可以使用文件系统保存,甚至是使用网络;后端的多样 性给得程序的设计更富有弹性。
今天结合自己开发的经验,总结一下实现Content Provider的几点经验,不足之处,欢迎讨论
通过扩展 ContentProvider 类来创建一个新的 Content Provider 。重写 onCreate 方法来打开或初始化你要通过这个 Provider 提供的底层数据源。新的 Content Provider 的框架代码如下所示:
import android.content.*;
import android.database.Cursor;
import android.net.Uri;
import android.database.SQLException;
public class MyProvider extends ContentProvider
{
@Override
public boolean onCreate()
{
// TODO: Construct the underlying database.
return true;
}
}
你还应该暴露一个公共的静态变量 CONTENT_URI ,来返回这个 Provider 的 URI 。
Content URI 在 Provider 间必须是独一无二的,所以,一个好的习惯是: URI 路径值使用包名。定义一个 Content Provider URI 的通用格式是:
content://com.<CompanyName>.provider.<ApplicationName>/<DataPath>
例如:
content://com.paad.provider.myapp/items
Content URI 可以表示为两种形式。上面的 URI 表示请求某类型的全部值(例如,所有项目)。
在其后追加 /<rownumber> ,如下所示,表示请求单一记录(例如,第 5 个项目)。
content://com.paad.provider.myapp/items/5
支持这两种方式来访问你的 Provider 是个很好的形式。
做到这样最简单的方式是使用一个 UriMatcher 。当通过 ContentResolver 来访问一个 Provider 时,配置 UriMatcher 解析 URI 来决定它们的形式。下面的代码显示了这一样式的框架代码:
public class MyProvider extends ContentProvider
{
private static final String myURI =“content://com.paad.provider.myapp/items”;
public static final Uri CONTENT_URI = Uri.parse(myURI);
@Override
public boolean onCreate()
{
// TODO: Construct the underlying database.
return true;
}
// Create the constants used to differentiate between the different
// URI requests.
private static final int ALLROWS = 1;
private static final int SINGLE_ROW = 2;
private static final UriMatcher uriMatcher;
// Populate the UriMatcher object, where a URI ending in ‘items’ will
// correspond to a request for all items, and ‘items/[rowID]’
// represents a single row.
static
{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(“com.paad.provider.myApp”, “items”, ALLROWS);
uriMatcher.addURI(“com.paad.provider.myApp”, “items/#”,SINGLE_ROW);
}
}
你可以使用相同的技巧来暴露数据中不同子集的 URI 或数据库中不同的表的 URI 。
一个好的习惯是:在 Provider 中保留列的名称和索引,来简化通过 Cursor 提取信息。
暴露数据源的访问
你可以实现 delete 、 insert 、 update 和 query 方法来暴露与你的 Content Provider 的查询和交互功能。
这些方法作为底层数据源的通用接口,允许 Android 应用程序跨越程序边界来共享数据,而不需要为每个程序公布不同的接口。
最常见的场景是使用一个 Content Provider 来访问一个私有的 SQLite 数据库,但使用这些方法,你可以访问任何数据源(包括文件或应用程序实例的变量)。
接下来的框架代码显示了一个 Content Provider 的查询和交互功能。注意: UriMatcher 对象用于精炼交互和查询请求。
@Override
public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sort)
{
// If this is a row query, limit the result set to the passed in row.
switch (uriMatcher.match(uri))
{
case SINGLE_ROW :
// TODO: Modify selection based on row id, where:
// rowNumber = uri.getPathSegments().get(1));
}
return null;
}
@Override
public Uri insert(Uri _uri, ContentValues _initialValues) {
long rowID = [ ... Add a new item ... ]
// Return a URI to the newly added item.
if (rowID > 0)
{
return ContentUris.withAppendedId(CONTENT_URI, rowID);
}
throw new SQLException(“Failed to add new item into “ + _uri);
}
@Override
public int delete(Uri uri, String where, String[] whereArgs)
{
switch (uriMatcher.match(uri))
{
case ALLROWS:
case SINGLE_ROW:
default: throw new IllegalArgumentException(“Unsupported URI:” + uri);
}
}
@Override
public int update(Uri uri, ContentValues values, String where,String[] whereArgs)
{
switch (uriMatcher.match(uri))
{
case ALLROWS:
case SINGLE_ROW:
default: throw new IllegalArgumentException(“Unsupported URI:” + uri);
}
}
创建 Content Provider 最后一步是定义标识 Provider 返回数据的 MIME 类型。
重写 getType 方法,返回一个独一无二的字符串来描述你的数据类型。返回的类型必须包含两种形式,一种是单一项目,另一种是所有的项目,如下所示:
❑ 单一项目
vnd.<companyname>.cursor.item/<contenttype>
❑ 所有的项目
vnd.<companyName>.cursor.dir/<contenttype>
接下来的代码片段显示了如何重写 getType 方法来一句传入的 URI 来返回正确的 MIME 类型:
@Override
public String getType(Uri _uri)
{
switch (uriMatcher.match(_uri))
{
case ALLROWS: return “vnd.paad.cursor.dir/myprovidercontent”;
case SINGLE_ROW: return “vnd.paad.cursor.item/myprovidercontent”;
default: throw new IllegalArgumentException(“Unsupported URI: “ + _uri);
}
}
注册 Provider
一旦完成了 Content Provider ,你必须将其添加到应用程序的 manifest 中。使用 authorities 标签来指定它的路径,如下面的 XML 片段所示:
<provider android:name=”MyProvider” android:authorities=”com.paad.provider.myapp”/>