还可参考http://blog.youkuaiyun.com/jiahui524/article/details/7016430
ContentProvider(内容提供者)是Android中的四大组件之一。主要用于对外共享数据,也就是通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对指定应用中的数据进行操作。ContentProvider分为系统的和自定义的,系统的也就是例如联系人,图片等数据。
其中ContentProvider负责
- 组织应用程序的数据;
- 向其他应用程序提供数据;
ContentResolver则负责
- 获取ContentProvider提供的数据;
- 修改/添加/删除更新数据等;
ContentProvider 是如何向外界提供数据的?
Android提供了ContentProvider,一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据完全暴露出去,而且ContentProviders是以类似数据库中表的方式将数据暴露,也就是说ContentProvider就像一个“数据库”。那么外界获取其提供的数据,也就应该与从数据库中获取数据的操作基本一样,只不过是采用URI来表示外界需要访问的“数据库”。
ContentProvider 是如何组织数据的?
组织数据主要包括:存储数据,读取数据,以数据库的方式暴露数据。数据的存储需要根据设计的需求,选择合适的存储结构,首选数据库,当然也可以选择本地其他文件,甚至可以是网络上的数据。数据的读取,以数据库的方式暴露数据这就要求,无论数据是如何存储的,数据最后必须以数据的方式访问。
可能还有2个问题,是需要关注的。
- ContentProvider是什么时候创建的,是谁创建的?访问某个应用程序共享的数据,是否需要启动这个应用程序?这个问题在Android SDK中没有明确说明,但是从数据共享的角度出发,ContentProvider应该是Android在系统启动时就创建了,否则就谈不上数据共享了。这就要求在AndroidManifest.XML中使用<provider>元素明确定义。
- 可能会有多个程序同时通过ContentResolver访问一个ContentProvider,会不会导致像数据库那样的“脏数据”?这个问题一方面需要数据库访问的同步,尤其是数据写入的同步,在AndroidManifest.XML中定义ContentProvider的时候,需要考虑是<provider>元素multiprocess属性的值;另外一方面Android在ContentResolver中提供了notifyChange()接口,在数据改变时会通知其他ContentObserver,这个地方应该使用了观察者模式,在ContentResolver中应该有一些类似register,unregister的接口。
至此,已经对ContentProvider提供了比较全面的分析,至于如何创建ContentProvider,可通过2种方法:创建一个属于你自己的ContentProvider或者将你的数据添加到一个已经存在的ContentProvider中,当然前提是有相同数据类型并且有写入Content provider的权限。
转载 http://www.moandroid.com/?p=157以下这段是Google Doc中对ContentProvider的大致概述。
内容提供者将一些特定的应用程序数据供给其它应用程序使用。数据可以存储于文件系统、SQLite数据库或其它方式。内容提供者继承于ContentProvider 基类,为其它应用程序取用和存储它管理的数据实现了一套标准方法。然而,应用程序并不直接调用这些方法,而是使用一个 ContentResolver 对象,调用它的方法作为替代。ContentResolver可以与任意内容提供者进行会话,与其合作来对所有相关交互通讯进行管理。
1.ContentProvider
Android提供了一些主要数据类型的ContentProvider,比如音频、视频、图片和私人通讯录等。可在android.provider包下面找到一些Android提供的ContentProvider。通过获得这些ContentProvider可以查询它们包含的数据,当然前提是已获得适当的读取权限。
主要方法:
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中的数据的MIME类型
*如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头。
例如:要得到所有person记录的Uri为content://contacts/person,那么返回的MIME类型字符串为"vnd.android.cursor.dir/person"。
*如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头。
例如:要得到id为10的person记录的Uri为content://contacts/person/10,那么返回的MIME类型字符串应为"vnd.android.cursor.item/person"。
2.ContentResolver
当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver类来完成,要获取ContentResolver对象,可以使用Context提供的getContentResolver()方法。
- ContentResolver cr = getContentResolver();
ContentResolver提供的方法和ContentProvider提供的方法对应的有以下几个方法。
public Uri insert(Uri uri, ContentValues values) 用于添加数据到指定Uri的ContentProvider中。
public int delete(Uri uri, String selection, String[] selectionArgs) 用于从指定Uri的ContentProvider中删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 用于更新指定Uri的ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 用于查询指定Uri的ContentProvider。
3.Uri
Uri指定了将要操作的ContentProvider,其实可以把一个Uri看作是一个网址,我们把Uri分为三部分。
第一部分是"content://"。可以看作是网址中的"http://"。
第二部分是主机名或authority,用于唯一标识这个ContentProvider,外部应用需要根据这个标识来找到它。可以看作是网址中的主机名,比如"blog.youkuaiyun.com"。
第三部分是路径名,用来表示将要操作的数据。可以看作网址中细分的内容路径。
下面是用ContentProvider读取联系人数据,属于系统数据。完整代码下载:android_contentprovider_system.rar
注意:这里的联系人操作有点乱,关键是我还不是很熟,SDK1.6和SDK2.1的联系人操作很有很大不同,希望哪位大侠指点一下。
- /**
- * MainActivity
- *
- * @author zuolongsnail
- */
- public class MainActivity extends Activity {
- private EditText nameET;
- private EditText numberET;
- private Button insertBtn;
- private Button deleteBtn;
- private Button queryBtn;
- private ListView contentView;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- nameET = (EditText) findViewById(R.id.name);
- numberET = (EditText) findViewById(R.id.number);
- insertBtn = (Button) findViewById(R.id.insert);
- deleteBtn = (Button) findViewById(R.id.delete);
- queryBtn = (Button) findViewById(R.id.query);
- // 用于显示数据
- contentView = (ListView) findViewById(R.id.content);
- insertBtn.setOnClickListener(new OperateOnClickListener());
- deleteBtn.setOnClickListener(new OperateOnClickListener());
- queryBtn.setOnClickListener(new OperateOnClickListener());
- }
- class OperateOnClickListener implements OnClickListener {
- @Override
- public void onClick(View v) {
- String name = nameET.getText().toString();
- String number = numberET.getText().toString();
- Person p = new Person(name, number);
- switch (v.getId()) {
- // 插入数据
- case R.id.insert:
- insert(p);
- view();
- break;
- // 删除数据
- case R.id.delete:
- delete(name);
- view();
- break;
- // 查询数据
- case R.id.query:
- view();
- break;
- }
- }
- }
- // 显示数据
- private void view() {
- Cursor c = query("");
- ListAdapter listAdapter = new SimpleCursorAdapter(this, R.layout.list,
- c, new String[] { People._ID, People.NAME, People.NUMBER },
- new int[] { R.id.id, R.id.name, R.id.number });
- contentView.setAdapter(listAdapter);
- }
- // 插入联系人
- private void insert(Person p) {
- // 获得ContentResolver对象
- ContentResolver cr = getContentResolver();
- ContentValues values = new ContentValues();
- values.put(People.NAME, p.name);
- // 表示是否把联系人添加到收藏(加星),1表示加入,0表示不加入,这行代码注释默认是不加入。
- values.put(Contacts.People.STARRED, 1);
- Uri uri = Contacts.People.createPersonInMyContactsGroup(cr, values);
- // 获得联系人People表的Uri
- Uri url = Uri.withAppendedPath(uri,
- Contacts.People.Phones.CONTENT_DIRECTORY);
- values.clear();
- values.put(Contacts.Phones.TYPE, Contacts.Phones.NUMBER);
- values.put(Contacts.Phones.NUMBER, p.number);
- // 插入操作
- cr.insert(url, values);
- }
- // 插入联系人
- private void delete(String name) {
- // 获得ContentResolver对象
- ContentResolver cr = getContentResolver();
- Uri url = Contacts.People.CONTENT_URI;
- // 设置删除条件
- String where = People.NAME + "=?";
- String[] selectionArgs = { name };
- cr.delete(url, where, selectionArgs);
- }
- // 查询联系人
- private Cursor query(String name) {
- // 获得ContentResolver对象
- ContentResolver cr = getContentResolver();
- Uri uri = Contacts.People.CONTENT_URI;
- // 查询对象
- String[] projection = { People._ID, People.NAME, People.NUMBER };
- // 设置查询条件,这里我把selection和selectionArgs参数都设为null,表示查询全部数据
- String selection = null;
- String[] selectionArgs = null;
- if (!"".equals(name)) {
- selection = People.NAME + "=?";
- selectionArgs = new String[] { name };
- }
- // 设置排序条件
- String sortOrder = Contacts.People._ID;
- Cursor c = cr.query(uri, projection, selection, selectionArgs,
- sortOrder);
- // if (c.moveToFirst()) {
- // for (int i = 0; i < c.getCount(); i++) {
- // c.moveToPosition(i);
- // String name = c.getString(c.getColumnIndexOrThrow(People.NAME));
- // String number = c.getString(c
- // .getColumnIndexOrThrow(People.NUMBER));
- // }
- // }
- return c;
- }
- }
程序截图:
转载http://blog.youkuaiyun.com/zuolongsnail/article/details/6566317
以下转载http://www.cnblogs.com/linjiqin/archive/2011/05/28/2061396.html
一、UriMatcher类使用介绍
因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher和ContentUris 。掌握它们的使用,会便于我们的开发工作。
UriMatcher类用于匹配Uri,它的用法如下:
首先第一步把你需要匹配Uri路径全部给注册上,如下:
// 常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码 UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH); // 如果match()方法匹配content: // com.ljq.provider.personprovider/person路径,返回匹配码为1 sMatcher.addURI( " com.ljq.provider.personprovider " , " person " , 1 ); // 添加需要匹配uri,如果匹配就会返回匹配码 // 如果match()方法匹配content: // com.ljq.provider.personprovider/person/230路径,返回匹配码为2 sMatcher.addURI( " com.ljq.provider.personprovider " , " person/# " , 2 ); // #号为通配符 switch (sMatcher.match(Uri.parse( " content://com.ljq.provider.personprovider/person/10 " ))) { case 1 break ; case 2 break ; default : // 不匹配 break ; }
注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配content://com.ljq.provider.personprovider/person路径,返回的匹配码为1
二、ContentUris类使用介绍
ContentUris类用于操作Uri路径后面的ID部分,它有两个比较实用的方法:
withAppendedId(uri, id)用于为路径加上ID部分:
Uri uri = Uri.parse( " content://com.ljq.provider.personprovider/person " ) Uri resultUri = ContentUris.withAppendedId(uri, 10 ); // 生成后的Uri为:content: // com.ljq.provider.personprovider/person/10
parseId(uri)方法用于从路径中获取ID部分:
Uri uri = Uri.parse( " content://com.ljq.provider.personprovider/person/10 " ) long personid = ContentUris.parseId(uri); // 获取的结果为:10
三、监听ContentProvider中数据的变化
如果ContentProvider的访问者需要知道ContentProvider中的数据发生变化,可以在ContentProvider发生数据变化时调用getContentResolver().notifyChange(uri, null)来通知注册在此URI上的访问者,例子如下:
public class PersonContentProvider extends ContentProvider { public Uri insert(Uri uri, ContentValues values) { db.insert( " person " , " personid " , values); getContext().getContentResolver().notifyChange(uri, null ); } }
如果ContentProvider的访问者需要得到数据变化通知,必须使用ContentObserver对数据(数据采用uri描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserver的onChange()方法:
getContentResolver().registerContentObserver(Uri.parse( " content://com.ljq.providers.personprovider/person " ), true , new PersonObserver( new Handler())); public class PersonObserver extends ContentObserver{ public PersonObserver(Handler handler) { super (handler); } public void onChange( boolean selfChange) { // 此处可以进行相应的业务处理 } }