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使用方法,包括最简单的用法,一个项目中创建多个ContentProvider分别操作数据库表,以及一个ContentProvider操作多张数据库表的用法。
android contentprovider使用示例
ContentProvider使用案例,ContentProvider使用案例,ContentProvider使用案例
ContentProvider使用,比较详细地讲解了ContentProvider使用的方法和例子。可以作为参考学习!
ContentProvider自定义以及使用系统ContentProvider
ContentProvider的应用:查询通讯录的联系人信息。
ContentProvider使用详细描述,可以给刚入门的兄弟做些指点。
ContentProvider 与 ContentResovler 进行应用间数据共享
android-关于ContentProvider的使用例子 有详细注释
1、Android Room操作SQLite数据 2、ContentProvider使用,使用Room进行数据库操作
Android知识点ContentProvider篇
ContentProvider使用简介里面的demo
在android中自定义一个ContentProvider大致需要四步:1,定义数据的MetaData;2,定义一个类继承ContentProvider;3,覆写自定义类中的getType(),onCreate(),insert(),delete(),update(),query()六个方法;4,在...