ContentProvider在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对你应用中的数据进行添删改查。
ContentProvider的优点:如果采用文件操作模式对外共享数据,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一,如:采用xml文件对外共享数据,需要xml解析才能读取数据;用sharedpreferences共享数据,需要使用sharedpreferences API读取数据。使用ContentProvider对外共享数据的好处是统一了数据的访问方式。
package com.test; import java.util.HashMap; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.text.TextUtils; public class MyProvider extends ContentProvider { //如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头, public static final String MIME_DIR_PREFIX = "vnd.android.cursor.dir"; //如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头, public static final String MIME_ITEM_PREFIX = "vnd.android.cursor.item"; public static final String MIME_ITEM = "vnd.msi.people"; public static final String MIME_TYPE_SINGLE = MIME_ITEM_PREFIX + "/" + MIME_ITEM; public static final String MIME_TYPE_MULTIPLE = MIME_DIR_PREFIX + "/" + MIME_ITEM; /* * 主机名(或叫Authority)用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它 * 和androidmanifest.xml中声明的一样 */ public static final String AUTHORITY = "com.test.provider"; public static final String PATH_SINGLE = "people/#"; public static final String PATH_MULTIPLE = "people"; /* * Uri代表了要操作的数据,Uri主要包含了两部分信息:1.需要操作的ContentProvider * 2.对ContentProvider中的什么数据进行操作,一个Uri由scheme,Authority,path三部分组成 * 其中scheme由Android所规定, scheme为:content:// * Authority用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。 * 和androidmanifest.xml中声明的一样 * path可以用来表示我们要操作的数据,路径的构建应根据如下规定: * 1.要操作person表中id为10的记录,可以构建这样的路径:/person/10 * 2.要操作person表中id为10的记录的name字段, person/10/name * 3. 要操作person表中的所有记录,可以构建这样的路径:/person * 4.要操作xxx表中的记录,可以构建这样的路径:/xxx * 5.当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下: * 6.要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name * 7.如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下: */ public static final Uri content_URI = Uri.parse("content://" + AUTHORITY + "/" + PATH_MULTIPLE); //指定查询结果按升序排列 public static final String DEFAULT_SORT_ORDER = "name DESC"; public static final int PEOPLE = 1; public static final int PEOPLES = 2; private static UriMatcher URI_MATCHER; private static HashMap<String, String> PROJECTION_MAP; public static String DB_NAME = "peopledb"; public static String DB_TABLE_NAME = "people"; SQLiteDatabase db; DBOpenHelper dbOpenHelper; /* * 内部类DBOpenHelper */ class DBOpenHelper extends SQLiteOpenHelper { private final String DB_CREATE = "CREATE TABLE " + DB_TABLE_NAME + " (_id INTEGER PRIMARY KEY,name TEXT UNIQUE NOT NULL," + "phone TEXT,age INTEGER);"; public DBOpenHelper(Context context, String dbName, int version) { super(context, dbName, null, version); } public void onCreate(SQLiteDatabase db) { try { db.execSQL(DB_CREATE); } catch (SQLException e) { e.printStackTrace(); } } public void onOpen(SQLiteDatabase db) { super.onOpen(db); } public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } } /* * 静态块 */ static { URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); /* * 如果match()方法匹配content://com.test.provider/people/# 路径(其中“#”号是通配符) * 返回匹配码为1 */ URI_MATCHER.addURI(AUTHORITY, PATH_SINGLE, PEOPLE); //如果match()方法匹配content://com.test.provider/people路径,返回匹配码为2 URI_MATCHER.addURI(AUTHORITY, PATH_MULTIPLE, PEOPLES); PROJECTION_MAP = new HashMap<String, String>(); PROJECTION_MAP.put("ID", "_id"); PROJECTION_MAP.put("NAME", "name"); PROJECTION_MAP.put("PHONE", "phone"); PROJECTION_MAP.put("AGE", "age"); } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { int count = 0; switch (URI_MATCHER.match(uri)) { case PEOPLES: count = db.delete(DB_TABLE_NAME, selection, selectionArgs); break; case PEOPLE: String segment = uri.getPathSegments().get(1); String where = ""; if (!TextUtils.isEmpty(selection)) { where = " AND (" + selection + ")"; } //删除具体某一条 count = db.delete(DB_TABLE_NAME, "_id=" + segment + where, selectionArgs); break; default: break; } /* * 如果ContentProvider的访问者需要知道ContentProvider中的数据发生变化, * 可以在ContentProvider发生数据变化时调 * 用getContentResolver().notifyChange(uri, null)来通知注册在此URI上的访问者 * 如果ContentProvider的访问者需要得到数据变化通知,必须使用ContentObserver对 * 数 据(数据采用uri描述)进行监听,当监听到数据变化通知时, * 系统就会调用ContentObserver的onChange()方法,具体实现如下: * getContentResolver().registerContentObserver(Uri.parse("content://com.test * .provider/people"), true, new PeopleObserver(new Handler())); public class PeopleObserver extends ContentObserver{ public PersonObserver(Handler handler) { super(handler); } public void onChange(boolean selfChange) { //此处可以进行相应的业务处理 } } */ getContext().getContentResolver().notifyChange(uri, null); return count; } @Override public String getType(Uri uri) { // TODO Auto-generated method stub switch (URI_MATCHER.match(uri)) { case PEOPLES: return MIME_TYPE_MULTIPLE; case PEOPLE: return MIME_TYPE_SINGLE; default: throw new IllegalArgumentException("Unkown URI " + uri); } } @Override public Uri insert(Uri uri, ContentValues values) { long rowId = 0L; if (URI_MATCHER.match(uri) != PEOPLES) { throw new IllegalArgumentException("Unkown URI" + uri); } rowId = db.insert(DB_TABLE_NAME, null, values); if (rowId > 0) { /* * withAppendedId(content_URI, id)用于为路径加上ID部分 * 生成后的Uri为:content://com.test.provider/people/rowId */ Uri result = ContentUris.withAppendedId(content_URI, rowId); //通知数据变化 getContext().getContentResolver().notifyChange(result, null); return result; } else throw new SQLException("Failed to insert row into " + uri); } @Override public boolean onCreate() { dbOpenHelper = new DBOpenHelper(this.getContext(), DB_NAME, 1); db = dbOpenHelper.getWritableDatabase(); return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { /* * SQLiteQueryBuilder:SQL查询的辅助类 * 这个查询类似于一个标准的SQL查询,但是这个查询是SQLiteQueryBuilder 来发起的,而不是 * SQLiteDatabase 直接发起的,所以在参数方面略有不同。 * 这个函数为 query(SQLiteDatabase db, String[] projectionIn, String selection, * String[] selectionArgs, String groupBy, String having, String sortOrder, * String limit)下边将各个参数介绍一下。 * 第一个参数为要查询的数据库实例。 * 第二个参数是一个字符串数组,里边的每一项代表了需要返回的列名。 * 第三个参数相当于SQL语句中的where部分。 * 第四个参数是一个字符串数组,里边的每一项依次替代在第三个参数中出现的问号(?)。 * 第五个参数相当于SQL语句当中的groupby部分。 * 第六个参数相当于SQL语句当中的having部分。 * 第七个参数描述是怎么进行排序。 * 第八个参数相当于SQL当中的limit部分,控制返回的数据的个数。 */ SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); queryBuilder.setTables(DB_TABLE_NAME); queryBuilder.setProjectionMap(PROJECTION_MAP); switch (URI_MATCHER.match(uri)) { case PEOPLES: break; case PEOPLE: queryBuilder.appendWhere("_id=" + uri.getPathSegments().get(1)); break; default: throw new IllegalArgumentException("Unkonw URI" + uri); } String orderBy = null; if (TextUtils.isEmpty(sortOrder)) { orderBy = DEFAULT_SORT_ORDER; } else orderBy = sortOrder; Cursor c = queryBuilder.query(db, projection, selection, selectionArgs, null, null, orderBy); c.setNotificationUri(getContext().getContentResolver(), uri); return c; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int count = 0; switch (URI_MATCHER.match(uri)) { case PEOPLES: count = db.update(DB_TABLE_NAME, values, selection, selectionArgs); break; case PEOPLE: String segment = uri.getPathSegments().get(1); String where = ""; if (!TextUtils.isEmpty(selection)) { where = " AND (" + selection + ")"; } count = db.update(DB_TABLE_NAME, values, "_id=" + segment + where, selectionArgs); break; default: throw new IllegalArgumentException("Unkonw URI" + uri); } getContext().getContentResolver().notifyChange(uri, null); return count; } }
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.test" android:versionCode="1" android:versionName="1.0" > <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name="com.test.Hello" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name="MyProvider" android:authorities="com.test.provider" android:syncable="true" > </provider> </application> <uses-sdk android:minSdkVersion="7" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" /> <uses-permission android:name="android.permission.READ_CONTACTS" > </uses-permission> </manifest>
可以通过如下代码:调用MyProvider中的方法:
ContentValues values = new ContentValues(); values.put("name", “tester”); values.put("phone", "10086"); values.put("age", 23); Uri uri = getContentResolver().insert(MyProvider.content_URI,values);
相关推荐
简单的ContentProvider使用 #### 2.1 创建ContentProvider 创建ContentProvider需要继承`android.content.ContentProvider`类,并重写其关键方法,如`onCreate()`, `query()`, `insert()`, `update()`, `delete()...
本教程将深入讲解ContentProvider的使用方法,包括基础操作、多ContentProvider管理和多表操作。 首先,基础的ContentProvider用法涉及以下几个步骤: 1. **定义Uri匹配规则**:ContentProvider通过Uri(统一资源...
本示例将详细解释如何在Android中使用ContentProvider。 1. **ContentProvider基本概念** ContentProvider是Android系统提供的一种数据存储和访问机制,它允许应用程序之间进行数据交换,而无需暴露底层数据库或...
本教程将通过一个具体的示例,即查询通讯录联系人信息,深入解析ContentProvider的使用方法。我们将使用Eclipse作为集成开发环境进行演示。 首先,理解ContentProvider的基本概念。ContentProvider是Android系统...
### ContentProvider使用详解 #### 一、ContentProvider概述与实现 **ContentProvider** 是 Android 四大组件之一,主要用于在不同的应用程序之间实现数据共享。它不仅可以在应用内部使用,还能跨应用提供数据服务...
本篇文章将深入探讨如何自定义ContentProvider以及如何使用系统提供的ContentProvider。 首先,理解ContentProvider的基本概念至关重要。ContentProvider是Android系统中的一种机制,它封装了对数据的操作,如读取...
本教程将深入解析ContentProvider的使用及其源码,结合SQLite数据库和ContentResolver,帮助开发者更好地理解和运用这一核心功能。 一、ContentProvider基础 ContentProvider是一个抽象类,它是Android四大组件之...
下面我们将深入探讨ContentProvider的使用,并结合"ContentProviderApp1"和"ContentProviderApp2"这两个示例项目来阐述其核心概念。 1. **ContentProvider的基本结构** - `ContentProvider`是一个抽象类,你需要...
在这个主题中,我们将深入探讨ContentProvider的使用案例,以及如何通过它来实现跨应用的数据交换。 ContentProvider的核心功能是为其他应用程序提供对特定数据集的访问权限。这使得开发者能够安全地共享私有数据库...
SQLiteDemo2是可能包含的一个示例,展示了如何结合ContentProvider使用SQLite数据库。SQLite是Android内置的轻量级关系型数据库,适合存储结构化的数据。通过ContentProvider,你可以让其他应用查询或修改SQLite...