简介
ContentProvider 在Android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider 对你应用中的数据进行添删改查。关于数据共享,以前我们学习过文件操作模式,知道通过指定文件的操作模式为Context.MODE_WORLD_READABLE 或Context.MODE_WORLD_WRITEABLE同样也可以对外共享数据。那么,这里为何要使用ContentProvider 对外共享数据呢?是这样的,如果采用文件操作模式对外共享数据,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一,如:采用xml文件对外共享数据,需要进行xml解析才能读取数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读取数据。
使用ContentProvider对外共享数据的好处是统一了数据的访问方式。
ContentProvider的原理是按照一定规则暴露自己的接口给其它应用来访问自己应用的数据(其实就是自定义增删改查接口并暴露出去,让别的应用访问自己的数据)。
ContentResolver就是按照一定规则访问内容提供者的数据(其实就是调用内容提供者自定义的接口来操作它的数据)。
ContentProvider对外共享数据:
步骤
1. 定义一个类 继承 ContentProvider
2. 定义匹配规则 指定主机名 + path code urimatcher content://
3. 通过静态代码块添加匹配规则
4. 一定要记得在清单文件配置内容提供者 不要忘记加authorities
说明:
第一步继承ContentProvider需要重写下面方法:
public class PersonContentProvider extends ContentProvider{
public boolean onCreate()
public Uri insert(Uri uri, ContentValues values)
public int delete(Uri uri, String selection, String[] selectionArgs)
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
public String getType(Uri uri)}
第四步需要在AndroidManifest.xml使用<provider>对该ContentProvider进行配置,为了能让其他应用找到该ContentProvider , ContentProvider
采用了authorities(主机名/域名)对它进行唯一标识,你可以把 ContentProvider看作是一个网站(想想,网站也是提供数据者),authorities 就是他的域名:
<manifest .... >
<application android:icon="@drawable/icon" android:label="@string/app_name">
<provider android:name=".PersonContentProvider" android:authorities="cn.itcast.providers.personprovider"/>
</application>
</manifest>
ContentProvider类主要方法的作用:
public boolean onCreate()
该方法在ContentProvider创建后就会被调用, Android开机后, ContentProvider在其它应用第一次访问它时才会被创建。
public Uri insert(Uri uri, ContentValues values)
该方法用于供外部应用往ContentProvider添加数据。
public int delete(Uri uri, String selection, String[] selectionArgs)
该方法用于供外部应用从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
该方法用于供外部应用更新ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
该方法用于供外部应用从ContentProvider中获取数据。
public String getType(Uri uri)
该方法用于返回当前Url所代表数据的MIME类型。如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,
例如:要得到所有person记录的Uri为content://cn.itcast.provider.personprovider/person,那么返回的MIME类型字符串应该为:“vnd.android.cursor.dir/person”。如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,例如:得到id为10的person记录,Uri为content://cn.itcast.provider.personprovider/person/10,那么返回的MIME类型字符串应该为:“vnd.android.cursor.item/person”。
Uri介绍
Uri代表了要操作的数据,Uri主要包含了两部分信息:1》需要操作的ContentProvider ,2》对ContentProvider中的什么数据进行操作,一个Uri由以下几部分组成:
ContentProvider(内容提供者)的scheme已经由Android所规定, scheme为:content://
主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
要操作person表中id为10的记录,可以构建这样的路径:/person/10
要操作person表中id为10的记录的name字段, person/10/name
要操作person表中的所有记录,可以构建这样的路径:/person
要操作xxx表中的记录,可以构建这样的路径:/xxx
当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:
要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")
UriMatcher类使用介绍
因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 。
掌握它们的使用,会便于我们的开发工作。
UriMatcher类用于匹配Uri,它的用法如下:
首先第一步把你需要匹配Uri路径全部给注册上,如下:
//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//如果match()方法匹配content://cn.itcast.provider.personprovider/person路径,返回匹配码为1
sMatcher.addURI(“cn.itcast.provider.personprovider”, “person”, 1);//添加需要匹配uri,如果匹配就会返回匹配码
//如果match()方法匹配content://cn.itcast.provider.personprovider/person/230路径,返回匹配码为2
sMatcher.addURI(“cn.itcast.provider.personprovider”, “person/#”, 2);//#号为通配符
switch (sMatcher.match(Uri.parse("content://cn.itcast.provider.personprovider/person/10"))) {
case 1
break;
case 2
break;
default://不匹配
break;
}
注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,
假设匹配content://cn.itcast.provider.personprovider/person路径,返回的匹配码为1
代码示例
- package com.itheima.transaction;
-
- import android.content.ContentProvider;
- import android.content.ContentValues;
- import android.content.UriMatcher;
- import android.database.Cursor;
- import android.database.sqlite.SQLiteDatabase;
- import android.net.Uri;
-
- public class AccountProvider extends ContentProvider {
-
- private static final int QUEYSUCESS = 0;
- private static final int INSERTSUCESS = 1;
-
- private static final int UPDATESUCESS = 2;
-
- private static final int DELSUCESS = 3;
-
-
- static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
-
- private MyOpenHelper helper;
-
-
-
- static{
-
-
-
-
-
-
- matcher.addURI("com.itheima.contentprovider", "query", QUEYSUCESS);
-
- matcher.addURI("com.itheima.contentprovider", "insert", INSERTSUCESS);
-
- matcher.addURI("com.itheima.contentprovider", "update", UPDATESUCESS);
-
- matcher.addURI("com.itheima.contentprovider", "delete", DELSUCESS);
-
-
- }
-
-
- @Override
- public boolean onCreate() {
- helper = new MyOpenHelper(getContext());
-
-
-
- return false;
- }
-
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
-
- int match = matcher.match(uri);
- if (match == QUEYSUCESS ) {
-
- SQLiteDatabase db = helper.getReadableDatabase();
- Cursor cursor = db.query("info", projection, selection, selectionArgs, null, null, sortOrder);
-
-
-
-
- getContext().getContentResolver().notifyChange(uri, null);
-
- return cursor;
-
- }else{
-
- throw new IllegalArgumentException("路径匹配失败");
-
- }
-
-
- }
-
- @Override
- public String getType(Uri uri) {
- return null;
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
-
- int match = matcher.match(uri);
- if (match == INSERTSUCESS) {
-
- SQLiteDatabase db = helper.getReadableDatabase();
- long insert = db.insert("info", null, values);
-
-
-
- if (insert>0) {
-
-
- getContext().getContentResolver().notifyChange(uri, null);
- }
-
-
-
-
- Uri uri2 = Uri.parse("com.itheima.contentprovider/"+insert);
- return uri2;
- }else{
-
- throw new IllegalArgumentException("路径匹配失败");
-
- }
-
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- int match = matcher.match(uri);
- if (match == DELSUCESS) {
-
- SQLiteDatabase db = helper.getReadableDatabase();
- int delete = db.delete("info", selection, selectionArgs);
-
- if (delete>0) {
-
- getContext().getContentResolver().notifyChange(uri, null);
-
- }
-
-
- return delete;
-
- }else {
-
-
- throw new IllegalArgumentException("路径匹配失败");
-
- }
-
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection,
- String[] selectionArgs) {
-
- int match = matcher.match(uri);
- if (match == UPDATESUCESS) {
-
- SQLiteDatabase db = helper.getReadableDatabase();
- int update = db.update("info", values, selection, selectionArgs);
-
- if (update>0) {
-
- getContext().getContentResolver().notifyChange(uri, null);
- }
-
- return update;
- }else {
-
- throw new IllegalArgumentException("路径匹配失败");
- }
-
- }
-
- }
内容解析者ContentResolver
使用ContentResolver调用ContentProvider提供的接口,操作数据
当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,
可以使用Activity提供的getContentResolver()方法。 ContentResolver 类提供了与ContentProvider类相同签名的四个方法:
public Uri insert(Uri uri, ContentValues values)
该方法用于往ContentProvider添加数据。
public int delete(Uri uri, String selection, String[] selectionArgs)
该方法用于从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
该方法用于更新ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
该方法用于从ContentProvider中获取数据。
这些方法的第一个参数为Uri,代表要操作的ContentProvider和对其中的什么数据进行操作,假设给定的是: Uri.parse(“content://cn.itcast.providers.personprovider/person/10”),那么将会对主机名为cn.itcast.providers.personprovider的ContentProvider进行操作,操作的数据为person表中id为10的记录。
- 使用ContentResolver对ContentProvider中的数据进行添加、删除、修改和查询操作:
- ContentResolver resolver = getContentResolver();
- Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person");
-
- ContentValues values = new ContentValues();
- values.put("name", "itcast");
- values.put("age", 25);
- resolver.insert(uri, values);
-
- Cursor cursor = resolver.query(uri, null, null, null, "personid desc");
- while(cursor.moveToNext()){
- Log.i("ContentTest", "personid="+ cursor.getInt(0)+ ",name="+ cursor.getString(1));
- }
-
- ContentValues updateValues = new ContentValues();
- updateValues.put("name", "liming");
- resolver.update(updateIdUri, updateValues, null, null);
监听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://cn.itcast.providers.personprovider/person"),
- true,
- new PersonObserver(new Handler()));
- public class PersonObserver extends ContentObserver{
- public PersonObserver(Handler handler) {
- super(handler);
- }
- public void onChange(boolean selfChange) {
-
- }
- }
实例代码
利用内容解析者备份短信
- package com.itheima.backupsms;
-
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
-
- import org.xmlpull.v1.XmlSerializer;
-
- import android.net.Uri;
- import android.os.Bundle;
- import android.os.Environment;
- import android.os.FileObserver;
- import android.app.Activity;
- import android.database.Cursor;
- import android.util.Xml;
- import android.view.Menu;
- import android.view.View;
-
- public class MainActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- }
-
-
-
-
-
-
- public void backup(View v) {
-
- try {
-
- XmlSerializer serializer = Xml.newSerializer();
-
- File file = new File(Environment.getExternalStorageDirectory()
- .getPath(), "smsbackup.xml");
- FileOutputStream fos = new FileOutputStream(file);
- serializer.setOutput(fos, "utf-8");
-
-
- serializer.startDocument("utf-8", true);
-
-
- serializer.startTag(null, "smss");
-
- Uri uri = Uri.parse("content://sms");
-
- Cursor cursor = getContentResolver().query(uri,
- new String[] { "address", "date", "body" }, null, null,
- null);
- while (cursor.moveToNext()) {
-
- serializer.startTag(null, "sms");
- String address = cursor.getString(0);
- String date = cursor.getString(1);
- String body = cursor.getString(2);
-
-
- serializer.startTag(null, "address");
- serializer.text(address);
- serializer.endTag(null, "address");
-
-
- serializer.startTag(null, "date");
- serializer.text(date);
- serializer.endTag(null, "date");
-
-
-
- serializer.startTag(null, "body");
- serializer.text(body);
- serializer.endTag(null, "body");
-
- serializer.endTag(null, "sms");
- }
-
-
-
- serializer.endTag(null, "smss");
-
-
- serializer.endDocument();
-
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- }
-
- }
利用内容解析者插入短信
-
- Uri uri = Uri.parse("content://sms");
- ContentValues values = new ContentValues();
- values.put("address", "110");
- values.put("date", System.currentTimeMillis());
- values.put("body", "您的事犯了 请您马上来一趟");
- getContentResolver().insert(uri, values);
利用内容解析者获取联系人数据
1. 首先 我要查询raw_contacts表 获取到 contact_id
2. 去data表 根据 contact_id 去获取 mimetype data1的数据
3. 然后根据 mimetype_id 来区分数据类型
- package com.itheima.getcontactinfo.utils;
-
- import java.util.ArrayList;
- import java.util.List;
-
- import android.content.ContentResolver;
- import android.content.Context;
- import android.database.Cursor;
- import android.net.Uri;
-
- import com.itheima.getcontactinfo.domain.ContactInfo;
-
- public class ContactUtils {
-
- public static List<ContactInfo> getContactInfos(Context context) {
-
- List<ContactInfo> contactLists = new ArrayList<ContactInfo>();
-
-
- Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
- Uri datauri = Uri.parse("content://com.android.contacts/data");
-
- ContentResolver resolver = context.getContentResolver();
- Cursor cursor = resolver.query(uri, new String[] { "contact_id" },
- null, null, null);
- while (cursor.moveToNext()) {
-
- String contact_id = cursor.getString(0);
- System.out.println("contact_id--" + contact_id);
-
-
- if (contact_id != null) {
-
- ContactInfo info = new ContactInfo();
- info.setId(contact_id);
-
-
-
- Cursor dataCursor = resolver.query(datauri, new String[] {
- "mimetype", "data1" }, "raw_contact_id=?",
- new String[] { contact_id }, null);
- while (dataCursor.moveToNext()) {
- String mimetype = dataCursor.getString(0);
- String data1 = dataCursor.getString(1);
-
-
- if ("vnd.android.cursor.item/email_v2".equals(mimetype)) {
- info.setEmail(data1);
-
- } else if ("vnd.android.cursor.item/name".equals(mimetype)) {
-
- info.setName(data1);
-
- } else if ("vnd.android.cursor.item/phone_v2"
- .equals(mimetype)) {
- System.out.println("data---电话号码-" + data1);
- info.setPhone(data1);
- }
-
- }
- dataCursor.close();
- contactLists.add(info);
-
- }
-
- }
- cursor.close();
-
- return contactLists;
-
- }
-
- }
- package com.itheima.getcontactinfo.domain;
-
- public class ContactInfo {
-
- private String id;
- private String name;
- private String phone;
- private String email;
-
-
-
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getPhone() {
- return phone;
- }
- public void setPhone(String phone) {
- this.phone = phone;
- }
- public String getEmail() {
- return email;
- }
- public void setEmail(String email) {
- this.email = email;
- }
- @Override
- public String toString() {
- return "ContactInfo [id=" + id + ", name=" + name + ", phone=" + phone
- + ", email=" + email + "]";
- }
-
-
-
-
-
- }
利用内容解析者插入联系人
1. 先往raw_contacts 插入一条数据
2. 往data表插入数据 根据mimetype contact_id 往里插入数据
- package com.itheima.insert.contact;
-
- import android.net.Uri;
- import android.os.Bundle;
- import android.app.Activity;
- import android.content.ContentValues;
- import android.database.Cursor;
- import android.view.Menu;
- import android.view.View;
- import android.widget.EditText;
-
- public class MainActivity extends Activity {
-
- private EditText et_name;
- private EditText et_phone;
- private EditText et_email;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
-
- et_name = (EditText) findViewById(R.id.et_name);
- et_phone = (EditText) findViewById(R.id.et_phone);
- et_email = (EditText) findViewById(R.id.et_email);
-
-
-
-
- }
-
-
-
-
-
- public void click(View v){
-
-
- String name = et_name.getText().toString().trim();
- String phone = et_phone.getText().toString().trim();
- String email = et_email.getText().toString().trim();
-
-
- Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
- Uri datauri = Uri.parse("content://com.android.contacts/data");
-
- ContentValues values = new ContentValues();
-
- Cursor cursor = getContentResolver().query(uri, null, null, null, null);
- int count = cursor.getCount();
- int contact_id = count + 1;
-
- values.put("contact_id", contact_id);
- getContentResolver().insert(uri, values);
-
-
-
- ContentValues nameValues = new ContentValues();
- nameValues.put("data1", name);
- nameValues.put("mimetype", "vnd.android.cursor.item/name");
- nameValues.put("raw_contact_id", contact_id);
- getContentResolver().insert(datauri, nameValues);
-
- ContentValues phoneValues = new ContentValues();
- phoneValues.put("data1", phone);
- phoneValues.put("mimetype", "vnd.android.cursor.item/phone_v2");
- phoneValues.put("raw_contact_id", contact_id);
- getContentResolver().insert(datauri, phoneValues);
-
- ContentValues emailValues = new ContentValues();
- emailValues.put("data1", email);
- emailValues.put("mimetype", "vnd.android.cursor.item/email_v2");
- emailValues.put("raw_contact_id", contact_id);
- getContentResolver().insert(datauri, emailValues);
-
-
-
-
-
- }
-
-
- }
利用监听和内容解析者监听短信
- package com.itheima.smslistener;
-
- import android.net.Uri;
- import android.os.Bundle;
- import android.os.Handler;
- import android.app.Activity;
- import android.database.ContentObserver;
- import android.database.Cursor;
- import android.view.Menu;
-
- public class MainActivity extends Activity {
-
- private Uri uri;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
-
-
- uri = Uri.parse("content://sms");
- getContentResolver().registerContentObserver(uri, true, new MyObserver(new Handler()));
-
- }
-
-
-
- private class MyObserver extends ContentObserver{
-
- public MyObserver(Handler handler) {
- super(handler);
- }
- @Override
- public void onChange(boolean selfChange) {
-
-
-
- Cursor cursor = getContentResolver().query(uri, new String[]{"address","body","date"}, null, null, null);
- while(cursor.moveToNext()){
-
- String address = cursor.getString(0);
- String body = cursor.getString(1);
- String date = cursor.getString(2);
-
- System.out.println("address---"+address+"--body:"+body);
-
- }
-
- super.onChange(selfChange);
- }
-
-
- }
-
- }