总结Content Provider的使用
来源:百度文库 编辑:神马文学网 时间:2024/04/27 18:18:19
总结Content Provider的使用
Provider, Content 本帖最后由 feng_home 于 2010-8-14 08:15 编辑Android中的Content provider机制可支持在多个应用中存储和读取数据。这也是跨应用共享数据的唯一方式。在android系统中,没有一个公共的内存区域,供多个应用共享存储数据。
Android提供了一些主要数据类型的Content provider,比如音频、视频、图片和私人通讯录等。可在android.provider包下面找到一些android提供的Content provider。可以获得这些Content provider,查询它们包含的数据,当然前提是已获得适当的读取权限。
如果想公开自己的数据,那么可有两种办法:
- 创建自己的Content provider,需要继承ContentProvider类;
- 如果你的数据和已存在的Content provider数据结构一致,可以将数据写到已存在的Content provider中,当然前提是获取写该Content provider的权限。比如把OA中的成员通讯信息加入到系统的联系人Content provider中。
- ContentResolver cr = getContentResolver();
ContentResolver实例带的方法可实现找到指定的Content provider并获取到Content provider的数据。ContentResolver的查询过程开始,Android系统将确定查询所需的具体Content provider,确认它是否启动并运行它。android系统负责初始化所有的Content provider,不需要用户自己去创建。实际上,content provider的用户都不可能直接访问到content provider实例,只能通过ContentResolver在中间代理。数据模型Content provider展示数据类似一个单个数据库表。其中:
- 每行有个带唯一值的数字字段,名为_ID,可用于对表中指定记录的定位;
- Content provider返回的数据结构,是类似JDBC的ResultSet,在android中,是Cursor对象。
- content://
表示这个uri指定一个content provider。如果你想创建自己的content provider,最好把自定义的URI设置为类的常量,这样简化别人的调用,并且以后如果更新URI也很容易。android定义了CONTENT_URI常量用于URI,比如:
- android.provider.Contacts.Phones.CONTENT_URI
- android.provider.Contacts.Photos.CONTENT_URI
要注意的是上面例子中的Contacts,已经在android 2.0及以上版本不赞成使用。查询Content provider要想使用一个content provider,需要以下信息:
- 定义这个content provider的URI
- 返回结果的字段名称
- 这些字段的数据类型
- Cursor cur = managedQuery(myPerson, null, null, null, null);
其中第一个参数myPerson是Uri类型实例。如果需要查询的是指定行的记录,需要用_ID值,比如ID值为23,URI将是类似:
- content://. . . ./23
android提供了方便的方法,让开发者不需要自己拼接上面这样的URI,比如类似:
- Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23);
或者:
- Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23");
二者的区别是一个接收整数类型的ID值,一个接收字符串类型。其他几个参数:
- names,可以为null,表示取数据集的全部列,或者声明一个String数组,数组中存放列名称,比如:People._ID。一般列名都在该Content provider中有常量对应;
- 针对返回结果的过滤器,格式类似于SQL中的WHERE子句,区别是不带WHERE关键字,如果返回null表示不过滤,比如name=?;
- 前面过滤器的参数,是String数组,是针对前面条件中?占位符的值;
- 排序参数,类似SQL的ORDER BY字句,不过不需要写ORDER BY部分,比如name desc,如果不排序,可输入null。
- Cursor cursor = getContentResolver().query(
- ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null,
- null,
- null);
返回值的内容 _ID _COUNT NAME NUMBER 44 3 Alan Vain 212 555 1234 13 3 Bully Pulpit 425 555 6677 53 3 Rex Cars 201 555 4433
返回值的内容类似上图,不同的content provider会有不同的列和名称,但是会有两个相同的列,上面提到过的一个是_ID,用于唯一标识记录,还有一个_COUNT,用于记录整个结果集的大小,可以看到上面图中的_COUNT的值是相同的。读取返回的数据如果在查询的时候使用到ID,那么返回的数据只有一条记录。在其他情况下,一般会有多条记录。和JDBC的ResultSet类似,需要操作游标遍历结果集,在每行,再通过列名获取到列的值,可以通过getString()、getInt()、getFloat()等方法获取值。比如类似下面:
- while (cursor.moveToNext()) {
- builder
- .append(
- cursor
- .getString(cursor
- .getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)))
- .append("-");
- }
和JDBC中不同,没有直接通过列名获取列值的方法,只能先列名获取到列的整型索引值,然后再通过该索引值定位获取列的值。编辑数据可以通过content provider实现以下编辑功能:
- 增加新的记录;
- 在已经存在的记录中增加新的值;
- 批量更新已经存在的多个记录;
- 删除记录。
- ContentValues values = new ContentValues();
- values.put(People.NAME, "Abraham Lincoln");
- Uri uri = getContentResolver().insert(People.CONTENT_URI, values);
在原有记录上增加值如果记录已经存在,可在记录上增加新的值,或者编辑已经存在的值。首先要过去到原来的值对象,然后要清除原有的值,然后像上面增加记录一样即可:
- Uri uri=Uri.withAppendedPath(People.CONTENT_URI, "23");
- Uri phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);
- values.clear();
- values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE);
- values.put(People.Phones.NUMBER, "1233214567");
- getContentResolver().insert(phoneUri, values);
批量更新值批量更新一组记录的值,比如NY改名为Eew York。可调用ContenResolver.update()方法。删除记录如果是删除单个记录,调用ContentResolver.delete()方法,URI参数,指定到具体行即可。如果是删除多个记录,调用ContentResolver.delete()方法,URI参数指定Content provider即可,并带一个类似SQL的WHERE子句条件。这里和上面类似,不带WHERE关键字。创建自己的Content provider创建content provider,需要:
- 设置存储系统。大多数content provider使用文件或者SQLite数据库,不过你可以用任何方式存储数据。android提供SQLiteoOpenHelper帮助开发者创建和管理SQLiteDatabase。
- 继承ContentProvider,提供对数据的访问。
- 在manifest文件中声明content provider。
insert()
update()
delete()
getType()
onCreate()query()方法,返回值是Cursor实例,用于迭代请求的数据。Cursor是一个接口。android为该接口提供了一些只读的(和JDBC的ResultSet不一样,后者还提供可写入的可选特性)Cursor实现。比如SQLiteCursor,可迭代SQLite数据库中的数据。可以通过SQLiteDatabase类的query()方法获取到该Cursor实例。还有其他的Cursor实现,比如MatrixCursor,用于数据不是存储在数据库的情况下。因为Content provider可能被多个ContentResolver对象在不同的进程和线程中调用,因此实现Content provider必须考虑线程安全问题。作为良好的习惯,在实现编辑数据的代码中,要调用ContentResolver.notifyChange()方法,通知那些监听数据变化的监听器。在实现子类的时候,还有一些步骤可以简化Content provider客户端的使用:定义public static final Uri常量,名称为CONTENT_URI:
- public static final Uri CONTENT_URI =
- Uri.parse("content://com.example.codelab.transportationprovider");
如果有多个表,它们也是使用相同的CONTENT_URI,只是它们的路径部分不同。
也就是说红色框部分是一致的。定义返回的列名,public static final,列名的值,比如使用SQLite数据库作为存储,对应表的列名。在文档中要写出各个列的数据类型,便于使用者读取。如果需要处理新的MIME数据类型,比如通过Intent的方式,并且带data的mimeType,那么需要在ContentProvider.getType()方法中进行处理。声明Content Provider创建Content Provider后,需要在manifest文件中声明,android系统才能知道它,当其他应用需要调用该Content Provider时才能创建或者调用它。语法类似:
- android:authorities="com.easymorse.cp.mycp">
android:name要写ContentProvider继承类的全名。android:authorities要写和CONTENT_URI常量的B部分(见上面图)。注意不要把上图C和D部分加到authorities中去。authorities是用来识别ContentProvider的,C和D部分实际上是ContentProvider内部使用的。
作为ANDROIDL四大组件(Compenent:Activity, Service, BreadcaseReceiver,
ContentProvider)之一的Content provider,为其它应用程序(也可以是提供该
Content provider的应用程序)提供了一个接口一致数据储存模型。通过该接口,你可以
方便地提取你想要的数据,修改或者是删除都会变得相当方便。依照ANDROI组件模型的原理,
把数据储存与数据显示分离天来,这不但提高了组件重用性,也同时提供更高的完全性(每一
个Content Provider都有自己的许可属性)。作为数据储存的后端,你可以使用有Sqlite3
保存数据,也可以使用文件系统保存,甚至是使用网络;后端的多样性给得程序的设计更富有
弹性。
今天结合自己开发的经验,总结一下实现Content Provider的几点经验,不足之处,欢迎
讨论(bangbang.song@gmail.com)
每一个实现都在从ContentProvider类继承,并实现ContentProvider的抽象函数:
delete(), insert(), query(), update(), getType()和onCreate().
代码片断:
- class myContentProvider extends ContentProvider {
- //删除符合指定条件的记录
- public int delete(Uri uri, String selection, String[] selectionArgs);
- //插入一个新的记录
- public Uri insert(Uri uri, ContentValues values);
- // 查询符合指定条件的记录
- public Cursor query(Uri uri, String[] projecttion, String selection, String[] selectionArgs, String sortOrder);
- //更新条例指定条件的记录
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs);
- //基于给定uri,返回该uri表示的类型
- public String getType(Uri uri);
- //创建数据储存后端,如数据库,文件,网络接口等
- public boolean onCreate();
- ......
- }
打开,更新,可以使用帮助类SQLiteHelper来完成,该类将对数据库的操作作了有效的封装,有利于我们使用。
代码片断:
- class youtDbHelper extends SQLiteHelper {
- // 创建数据库
- public void onCreate(SQLiteDatabase db);
- // 更新数据库
- public void onUpdate(SQLiteDatabase db, int oldVersion, int newVersion)
-
- ......
- }
与ContentProvider交流。在我们的ContentProvider创建好之后,我们不直接与之打交道,而是通过ANDROID的
ContentResolver进行操作。通过ANDROID系统的自动分析,会选择一个合适的ContentProvider进行通信。只要我们指定
我们之前定义的CONTENT_URI,就可能与之勾通了。
代码片断:
- Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);
- //或者
- Cursor cursor = manageQuery(uri, null, null, null, null);
- // 可以使用游标cursor获取想要的信息
- ...
- // 删除
- int count = getContentResolver().delete(Uri url, String where, String[] selectionArgs);
- ......
对Uri的说明:
Uri(unified Resource identifier)就是统一资源标识,指定了一个特定的资源,遵照RFC2396规范。
一般格式为:
<scheme>://
例如: content://your.contentprovider/what_u_provided
其中scheme=content 表示专为ContentProvider使用。 补充如下:
android有一个独特之处就是,数据库只能被它的创建者所使用,其他的应用是不能访问到的,所以如果你想实现不同应用之间的数据共享,就不得不用content
provider了。
在Android中,content
provider是一个特殊的存储数据的类型,它提供了一套标准的接口用来获取以及操作数据。并且,android自身也提供了几个现成的content
provider:Contacts,
Browser, CallLog, Settings, MediaStore.
应用可以通过一个唯一的ContentResolver
interface来使用具体的某个content
provider。
ContentResolver
cr = getContentResolver();
然后你就可以用ContentResolver提供的方法来使用你需要的content provider了。其中contentResolver提供的方法包括query(),insert(),update()等。要使用这些方法,还会涉及到一个东西,那就是Uri。你可以将它理解成一个string形式的contentProvider的完全路径,它的形式为:////,
例如:
content://browser/bookmarks
content://contacts/people
content://contacts/people/3
下面结合一个实例来看我们如何使用一个已有的content provider,给例子展示了如何从已有的电话本中读出联系人信息:
package com.android.cp;
import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.Contacts.People;
import android.util.Log;
import android.widget.Toast;
public class ContentProviderTest extends Activity {
private final String TAG = "ContentProviderTest";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG,"enter onCreate");
setContentView(R.layout.main);
createCP();
}
public void createCP()
{
ContentResolver cr = getContentResolver();
//Cursor cur = managedQuery(People.CONTENT_URI, null, null, null, null);
Cursor cur = cr.query(People.CONTENT_URI, null, null, null, null);
getColumnData(cur);
}
private void getColumnData(Cursor cur){
if (cur.moveToFirst()) {
String name;
String phoneNumber;
int nameColumn = cur.getColumnIndex(People.NAME);
int phoneColumn = cur.getColumnIndex(People.NUMBER);
do {
// Get the field values
name = cur.getString(nameColumn);
phoneNumber = cur.getString(phoneColumn);
Log.i(TAG, "name="+name);
DisplayToast(name+" "+phoneNumber);
} while (cur.moveToNext());
}
}
public void DisplayToast(String s)
{
Toast.makeText(this,
s,
Toast.LENGTH_LONG).show();
}
}
需要注意的是,你需要在你的Manifest文件中加上
uses-permission
android:name="android.permission.READ_CONTACTS">
/uses-permission>
否则,程序无法成功运行。
总结Content Provider的使用
总结Content Provider的使用
Heritrix使用的初步总结
Heritrix使用的初步总结
Heritrix使用的初步总结
Content-Disposition的使用方法
content
content
content
使用AppFuse进行开发的总结
有关TinyXML使用的简单总结
LEVE-2使用一年的心血总结
有关TinyXML使用的简单总结
DDX,DDY,DDZ指标的使用总结
“创建内容(content creation)”和“享用内容(content consumption)”两种不同使用模式
The ‘OraOLEDB.Oracle.1‘ provider is not registered on the local machine的原因
WORD使用技巧总结
Hessian学习/使用总结
powerpoint使用技巧总结
ppt幻灯片使用总结
Hessian学习/使用总结
TTS 使用总结
总结 GdiObject::DeleteObject()的使用 - TobyLin的学习之...
高手的均线总结及使用心得