1. 概述
ContentProvider 在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider 对你应用中的数据进行添删改查。关于数据共享,以前我们学习过文件操作模式,知道通过指定文件的操作模式为Context.MODE_WORLD_READABLE 或Context.MODE_WORLD_WRITEABLE同样也可以对外共享数据。那么,这里为何要使用ContentProvider 对外共享数据呢?是这样的,如果采用文件操作模式对外共享数据,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一,如:采用xml文件对外共享数据,需要进行xml解析才能读取数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读取数据。
使用ContentProvider对外共享数据的好处是统一了数据的访问方式。
当应用需要通过ContentProvider对外共享数据时,第一步需要继承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 就是他的域名:
<!--需要设定权限exported="true",其他程序可以调用-->
<provider
android:name="com.itheima.note.provider.NoteInfoProvider"
android:authorities="com.itheima.note.noteprovider"
android:exported="true">
</provider>
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”。
当外部应用需要对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的记录。
2. 示例代码
ContentProvider的建立, 在上篇SQLite的创建的基础上,
NoteInfoProvider.java, 建立 需要继承ContentProvider
public class NoteInfoProvider extends ContentProvider { private static final int QUERY = 1; private static final int INSERT = 2; private static final int DELETE = 3; private static final int UPDATE = 4; // 参数code 代表如果uri不匹配的返回值 // 在当前应用程序的内部 声明一个路径的检查者 private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); private SQLiteDatabase db; static { // 建立一个匹配规则 // 1.如果发现一个路径 com.itheima.note.noteprovider/query 查询的操作 matcher.addURI("com.itheima.note.noteprovider", "query", QUERY); matcher.addURI("com.itheima.note.noteprovider", "insert", INSERT); matcher.addURI("com.itheima.note.noteprovider", "delete", DELETE); matcher.addURI("com.itheima.note.noteprovider", "update", UPDATE); } @Override public boolean onCreate() { NoteSQLiteOpenHelper helper = new NoteSQLiteOpenHelper(getContext()); db = helper.getWritableDatabase(); return false; } /** * 内容提供者暴露的查询的方法. */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // 1.重要的事情 ,检查 uri的路径. int code = matcher.match(uri); if (code == QUERY) { // 查询处理 NoteSQLiteOpenHelper helper = new NoteSQLiteOpenHelper(getContext()); SQLiteDatabase db = helper.getReadableDatabase(); Cursor cursor = db.rawQuery("select * from account", null); //不要手动去关闭close db return cursor; } else { throw new IllegalArgumentException("路径不能被识别,我不认识你..."); } } //MIME 类型 @Override public String getType(Uri uri) { int code = matcher.match(uri); if (code == QUERY) { //返回一条数据 return "vnd.android.cursor.item/note"; //返回多条数据 //return "vnd.android.cursor.dir/note" } return null; } @Override public Uri insert(Uri uri, ContentValues values) { int code = matcher.match(uri); if (code == INSERT) { db.insert("account", null, values); } else { throw new IllegalArgumentException("路径不能被识别,我不认识你..."); } return null; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { int code = matcher.match(uri); if (code == DELETE) { db.delete("account", selection, selectionArgs); } else { throw new IllegalArgumentException("路径不能被识别,我不认识你..."); } return 0; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int code = matcher.match(uri); if (code == UPDATE) { db.update("account", values, selection, selectionArgs); } else { throw new IllegalArgumentException("路径不能被识别,我不认识你..."); } return 0; } }
AndroidManifest.xml, 需要配置provider 和 给权限
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.itheima.note" android:versionCode="1" android:versionName="1.0" > <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.itheima.note" /> <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <uses-library android:name="android.test.runner" /> <activity android:name="com.itheima.note.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!--需要设定权限exported="true",其他程序可以调用--> <provider android:name="com.itheima.note.provider.NoteInfoProvider" android:authorities="com.itheima.note.noteprovider" android:exported="true"> </provider> </application> </manifest>
MainActivity.java 其他App调用 内容提供者, 增删改查数据
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void query(View view){ //得到内容提供者的解析器 中间人 ContentResolver resolver = getContentResolver(); Uri uri = Uri.parse("content://com.itheima.note.noteprovider/query"); Cursor cursor = resolver.query(uri, null, null, null, null); while(cursor.moveToNext()){ String name = cursor.getString(cursor.getColumnIndex("name")); int id = cursor.getInt(cursor.getColumnIndex("id")); float money = cursor.getFloat(cursor.getColumnIndex("money")); System.out.println("id="+id+",name="+name+",money="+money); } cursor.close(); } public void insert(View view){ ContentResolver resolver = getContentResolver(); Uri uri = Uri.parse("content://com.itheima.note.noteprovider/insert"); ContentValues values = new ContentValues(); values.put("name", "买洗头膏"); values.put("money", 22.58f); resolver.insert(uri, values); } public void update(View view){ ContentResolver resolver = getContentResolver(); Uri uri = Uri.parse("content://com.itheima.note.noteprovider/update"); ContentValues values = new ContentValues(); values.put("name", "买洗头膏"); values.put("money", 42.58f); resolver.update(uri, values, "name=?", new String[]{"买洗头膏"}); } public void delete(View view){ ContentResolver resolver = getContentResolver(); Uri uri = Uri.parse("content://com.itheima.note.noteprovider/delete"); resolver.delete(uri, "name=?", new String[]{"买洗头膏"}); } }