Android内容提供者——Content Providers(一)

时间:2021-08-09 09:23:03

Content Providers是Android四大组件之一,扮演者非常重要的角色,看下官方文档对它的解释:


Content providers manage access to a structured set of data. They encapsulate the data, and provide mechanisms for defining data security. Content providers are the standard interface that connects data in one process with code running in another process.


可以看到Content providers负责管理结构化数据的访问,Content providers封装数据并且提供一套定义数据安全的机制。Content providers是一套在不同进程间进行数据访问的接口。

Content providers为数据跨进程访问提供了一套安全的访问机制,对数据组织和安全访问提供了可靠的保证。


另外来看看官方文档是如何解释Content Providers的使用的:

When you want to access data in a content provider, you use theContentResolver object in your application's Context to communicate with the provider as a client. The ContentResolverobject communicates with the provider object, an instance of a class that implements ContentProvider. The provider object receives data requests from clients, performs the requested action, and returns the results.


意思是当你想要通过Content Providers访问数据时,在应用程序的上下文(Context)中使用ContentResolver对象最为客户端(client)与provider进行交互。ContentResolver对象通过实现抽象类ContentProvider的一个实例来访问provider。Provider对象从客户端(client)接收数据请求,执行请求操作并且返回请求结果。


Android通过Content Provider来管理数据诸如音频、视频、图片和通讯录等。还可以通过ContentProvider来访问SQLite数据库等,下面来看看Content Provider的基本使用。


在此之前,官方文档中给出了一些是否需要需用Content Providers的建议:

Decide if you need a content provider. You need to build a content provider if you want to provide one or more of the following features:

  • You want to offer complex data or files to other applications.
  • You want to allow users to copy complex data from your app into other apps.
  • You want to provide custom search suggestions using the search framework.


在以下情况下你需要使用Content Providers:

1.你想为其他应用程序提供复杂数据或文件;

2.你想允许用户从你的应用程序中拷贝复杂数据到其他的应用中

3.你想使用搜索框架提供自定义的查询建议功能


Content Provider通过URI(统一资源定位符)来访问数据,URI可以理解为访问数据的唯一地址,URI由authority和数据地址构成,关于authority可以理解成网站地址中的主机地址,而数据地址可以理解成某一个页面的子地址,二者共同构成了一个完整的访问地址,关于authority的命名,官方文档中有这么一句话 If your Android package name iscom.example.<appname>, you should give your provider the authority com.example.<appname>.provider.可见对于authority的命名还是有一定的规范性的。

关于URI的格式:content://<authority>/<path>/<id>,path就是数据路径,比如说一张表,而id就是这张表中主键为id的一行,也可以理解成一个实体对象。


看下构建Content Provider和使用URI的代码:

publicclassExampleProviderextendsContentProvider{...
// Creates a UriMatcher object.
privatestaticfinalUriMatcher sUriMatcher;...
/*
* The calls to addURI() go here, for all of the content URI patterns that the provider
* should recognize. For this snippet, only the calls for table 3 are shown.
*/...
/*
* Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used
* in the path
*/
sUriMatcher.addURI("com.example.app.provider","table3",1);

/*
* Sets the code for a single row to 2. In this case, the "#" wildcard is
* used. "content://com.example.app.provider/table3/3" matches, but
* "content://com.example.app.provider/table3 doesn't.
* 这里说明了两种通配符的作用
* *: Matches a string of any valid characters of any length.
* #: Matches a string of numeric characters of any length.

*/
sUriMatcher.addURI("com.example.app.provider","table3/#",2);...
// Implements ContentProvider.query()
publicCursor query(
Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sortOrder){...
/*
* Choose the table to query and a sort order based on the code returned for the incoming
* URI. Here, too, only the statements for table 3 are shown.
*/
switch(sUriMatcher.match(uri)){


// If the incoming URI was for all of table3
case1:

if(TextUtils.isEmpty(sortOrder)) sortOrder ="_ID ASC";
break;

// If the incoming URI was for a single row
case2:

/*
* Because this URI was for a single row, the _ID value part is
* present. Get the last path segment from the URI; this is the _ID value.
* Then, append the value to the WHERE clause for the query
*/
selection = selection +"_ID = " uri.getLastPathSegment();
break;

default:
...
// If the URI is not recognized, you should do some error handling here.
}
// call the code to actually do the query }

实现抽象类ContentProvider后,有几个需要实现的方法:

query()

Retrieve data from your provider. Use the arguments to select the table to query, the rows and columns to return, and the sort order of the result. Return the data as a Cursor object.

insert()

Insert a new row into your provider. Use the arguments to select the destination table and to get the column values to use. Return a content URI for the newly-inserted row.

update()

Update existing rows in your provider. Use the arguments to select the table and rows to update and to get the updated column values. Return the number of rows updated.

delete()

Delete rows from your provider. Use the arguments to select the table and the rows to delete. Return the number of rows deleted.

getType()

Return the MIME type corresponding to a content URI. This method is described in more detail in the sectionImplementing Content Provider MIME Types.

onCreate()

Initialize your provider. The Android system calls this method immediately after it creates your provider. Notice that your provider is not created until a ContentResolver object tries to access it. 

举一个例子,如果使用SQLite作为Content Provider的数据源,下面这段代码片段建立了SQLiteOpenHelper的子类MainDatabaseHelper,并且生成了表main

// A string that defines the SQL statement for creating a tableprivatestaticfinalString SQL_CREATE_MAIN ="CREATE TABLE "+
"main "+ // Table's name
"("+ // The columns in the table
" _ID INTEGER PRIMARY KEY, "+
" WORD TEXT"
" FREQUENCY INTEGER "+
" LOCALE TEXT )";.../**
* Helper class that actually creates and manages the provider's underlying data repository.
*/protectedstaticfinalclassMainDatabaseHelperextendsSQLiteOpenHelper{

/*
* Instantiates an open helper for the provider's SQLite data repository
* Do not do database creation and upgrade here.
*/
MainDatabaseHelper(Context context){
super(context, DBNAME,null,1);
}

/*
* Creates the data repository. This is called when the provider attempts to open the
* repository and SQLite reports that it doesn't exist.
*/
publicvoid onCreate(SQLiteDatabase db){

// Creates the main table
db.execSQL(SQL_CREATE_MAIN);
} }

然后定义ContentProvider来操作数据库,这样,就建立了一套在数据源(SQLite)和客户端(client)之间的接口

publicclassExampleProviderextendsContentProvider

/*
* Defines a handle to the database helper object. The MainDatabaseHelper class is defined
* in a following snippet.
*/
privateMainDatabaseHelper mOpenHelper;

// Defines the database name
privatestaticfinalString DBNAME ="mydb";

// Holds the database object
privateSQLiteDatabase db;

publicboolean onCreate(){

/*
* Creates a new helper object. This method always returns quickly.
* Notice that the database itself isn't created or opened
* until SQLiteOpenHelper.getWritableDatabase is called
*/
mOpenHelper =newSQLiteOpenHelper(
getContext(), // the application context
DBNAME, // the name of the database)
null, // uses the default SQLite cursor
1 // the version number
);

returntrue;
}

...

// Implements the provider's insert method
publicCursor insert(Uri uri,ContentValues values){
// Insert code here to determine which table to open, handle error-checking, and so forth
/*
* Gets a writeable database. This will trigger its creation if it doesn't already exist.
*
*/
db = mOpenHelper.getWritableDatabase();
} }

简单的总结一些Content Providers:

1.Content Providers是Android系统中四大组件之一,提供一套在客户端(client)和数据源(data source)之间的访问接口

2.Content Providers可以提供跨进程访问数据的功能,能暴露本地数据给其他应用访问

3.实现Content Providers只需要继承抽象类ContentProvider并实现必要的抽象方法即可,访问ContentProvider则根据URI来访问


以上简单介绍了下ContentProvider,资料来源是Android官方文档,有不足之处还望指教

参考:http://developer.android.com/guide/topics/providers/content-providers.html


加入我们的QQ群或微信公众账号请查看: Ryan's zone公众账号及QQ群


欢迎关注我的新浪微博:@唐韧_Ryan