橘子味的心
标题:7.7 自定义ContentProvider

Android 系统支持任意应用程序创建自己的 ContentProvider,以便于将应用程序的数据对其他应用程序共享。

创建应用程序自己的 ContentProvider 需要以下几个步骤:

1)当前应用程序必须具有自己的持久化数据,例如文件存储或者使用 SQLite 数据库存储。

2)当前应用程序需要实现 ContentProvider 的子类,并通过该子类完成对持久化数据的访问。

3)在 AndroidManifest.xml 文件中使用 <provider> 标签声明当前应用程序定义的 ContentProvider。此外,还可以在 AndroidManifest.xml 文件中指定相应的访问权限,以保证该 ContentProvider 仅被具有相应权限的应用程序访问。若不指定访问权限,则任意其他应用程序都可以访问该 ContentProvider。

在实际的应用中,为了方便应用程序所定义的 ContentProvider 被其他应用程序使用,通常会定义一个类,将 ContentProvider 相关信息以静态常量的方式放置到该类中。这样,使用该 ContentProvider 的应用程序只要将该类引用进来,就可以获取该 ContentProvider 的相关信息,进而通过其对数据进行操作。

本节以 Android SQLite 数据库操作实例教程中使用的实例 MyDbDemo 为例,为该实例中创建的 SQLite 数据库 mydb 中的 friends 数据表创建 ContentProvider,以便于其他应用程序通过该 ContentProvider 对 friends 数据表中的数据进行访问。

在实例 MyDbDemo 中的 introduction.android.mydbDemo 包下创建两个文件,分别为 MyDbProvider.java 和 MyFriendsDB.java。

MyDbProvider 继承了 ContentProvider 类,实现了针对 mydb 的 friends 数据表的相关操作。MyFriendsDB 中包含涉及 MyDbProvider 的相关信息。

MyDbProvider.java 的代码如下:
  1. package introduction.android.mydbdemo;
  2.  
  3. import android.content.ContentProvider;
  4. import android.content.ContentUris;
  5. import android.content.ContentValues;
  6. import android.content.UriMatcher;
  7. import android.database.Cursor;
  8. import android.database.sqlite.SQLiteDatabase;
  9. import android.database.sqlite.SQLiteQueryBuilder;
  10. import android.net.Uri;
  11. import android.util.Log;
  12.  
  13. public class MyDbProvider extends ContentProvider {
  14. private dbHelper mydbHelper;
  15. private static final UriMatcher myUriMatcher;
  16.  
  17. static {
  18. myUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  19. myUriMatcher.addURI(MyFriendsDB.AUTHORITY, "friends", MyFriendsDB.FRIENDS);
  20. myUriMatcher.addURI(MyFriendsDB.AUTHORITY, "friends/#", MyFriendsDB.FRIENDS_ID);
  21. }
  22. @Override
  23. public int delete(Uri uri, String selection, String[] selectionArgs) {
  24. // TODO Auto-generated method stub
  25. if (myUriMatcher.match(uri) != MyFriendsDB.FRIENDS_ID) {
  26. throw new IllegalArgumentException("Wrong Insert Type: " + uri);
  27. }
  28. String id = uri.getPathSegments().get(1);
  29. if (selection == null)
  30. selection = MyFriendsDB.ID + "=" + id;
  31. else
  32. selection = MyFriendsDB.ID + "=" + id + " and " + selection;
  33. SQLiteDatabase db = mydbHelper.getWritableDatabase();
  34. int i = db.delete(dbHelper.TB_NAME, selection, selectionArgs);
  35. if (i > 0)
  36. Log.i("myDbDemo", "数据更新成功!");
  37. else
  38. Log.i("myDbDemo", "数据未更新!");
  39. return i;
  40. }
  41.  
  42. @Override
  43. public String getType(Uri uri) {
  44. // TODO Auto-generated method stub
  45. switch (myUriMatcher.match(uri)) {
  46. case MyFriendsDB.FRIENDS:
  47. return MyFriendsDB.CONTENT_TYPE;
  48. case MyFriendsDB.FRIENDS_ID:
  49. return MyFriendsDB.CONTENT_ITEM_TYPE;
  50. default:
  51. hrow new IllegalArgumentException("Unknown URI get type: " + uri);
  52. }
  53. }
  54.  
  55. @Override
  56. public Uri insert(Uri uri, ContentValues values) {
  57. // TODO Auto-generated method stub
  58. if (myUriMatcher.match(uri) != MyFriendsDB.FRIENDS) {
  59. throw new IllegalArgumentException("Wrong Insert Type: " + uri);
  60. }
  61. if (values == null) {
  62. throw new IllegalArgumentException("Wrong Data.");
  63. }
  64. SQLiteDatabase db = mydbHelper.getWritableDatabase();
  65. long rowId = db.insert(MyFriendsDB.TABLE_NAME, null, values);
  66. if (rowId > 0) {
  67. Uri insertUri = ContentUris.withAppendedId(MyFriendsDB.CONTENT_URI, rowId);
  68. return insertUri;
  69. }
  70. return null;
  71. }
  72.  
  73. @Override
  74. public boolean onCreate() {
  75. // TODO Auto-generated method stub
  76. mydbHelper = new dbHelper(getContext(),MyFriendsDB.DATABASE_NAME, null, MyFriendsDB.DATABASE_VERSI0N);
  77. return false;
  78. }
  79.  
  80. @Override
  81. public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {
  82. // TODO Auto-generated method stub
  83. switch (myUriMatcher.match(uri)) {
  84. case MyFriendsDB.FRIENDS:
  85. break;
  86. case MyFriendsDB.FRIENDS_ID:
  87.      Log.d("MyDbProvider", "select id");
  88.      String id = uri.getPathSegments().get(1);
  89.      if (selection == null)
  90.      selection = MyFriendsDB.ID + "=" + id;
  91.      else
  92.        selection = MyFriendsDB.ID + "=" + id + " and " + selection;
  93.        break;
  94.      default:
  95.        throw new IllegalArgumentException("Unknown URI type: " + uri);
  96. }
  97.  
  98. if (sortOrder == null)
  99. sortOrder = "_id ASC";
  100. SQLiteDatabase db = mydbHelper.getReadableDatabase();
  101. Cursor c = db.query(MyFriendsDB.TABLE_NAME, projection, selection, selectionArgs,null,null, sortOrder);
  102. Log.d("MyDbProvider", "" + c.getCount());
  103. return c;
  104.     }
  105.  
  106.     @Override
  107.     public int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {
  108. // TODO Auto-generated method stub
  109. if (myUriMatcher.match(uri) != MyFriendsDB.FRIENDS_ID) {
  110. throw new IllegalArgumentException("Wrong Insert Type: " + uri);
  111. }
  112. if (values == null) {
  113. throw new IllegalArgumentException("Wrong Data.");
  114. }
  115. String id = uri.getPathSegments().get(1);
  116. if (selection == null)
  117. selection = MyFriendsDB.ID + "=" + id;
  118. else
  119. selection = MyFriendsDB.ID + "=" + id + " and " + selection;
  120. SQLiteDatabase db = mydbHelper.getWritableDatabase();
  121. int i = db.update(dbHelper.TB_NAME, values, selection, selectionArgs);
  122. if (i > 0)
  123. Log.i("myDbDemo ", "数据更新成功! ");
  124. else
  125. Log.i("myDbDemo", "数据未更新!");
  126. return i;
  127. }
  128. }
MyFriendsDB.java 的代码如下:
  1. package introduction.android.mydbdemo;
  2.  
  3. import android.net.Uri;
  4.  
  5. public class MyFriendsDB {
  6.  
  7. public static final String AUTHORITY = "introduction.android.mydbdemo.myfriendsdb";
  8. public static final String DATABASE_NAME = "mydb";
  9. public static final int DATABASE_VERSI0N = 1;
  10. public static final String TABLE_NAME = "friends";
  11.  
  12. public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/friends");
  13. public static final int FRIENDS = 1;
  14. public static final int FRIENDS_ID = 2;
  15.  
  16. public static final String CONTENT_TYPE = "vnd.android.cursor.dir/mydb.friends.all";
  17. public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.dir/mydb.friends.item";
  18. public static final String ID = "_id";
  19.  
  20. public static final String NAME = "name";
  21. public static final String AGE = "age";
  22. }
这样,就定义了针对 mydb 的 friends 数据表的 ContentProvider,最后需要在 AndroidManifest.xml 文件中添加该 ContentProvider 的相应声明和访问权限。AndroidManifest.xml 的代码如下:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3.     package="introduction.android.mydbdemo"
  4.     android:versionCode="1"
  5.     android:versionName="1.0">
  6.  
  7.      uses-sdk android:minSdkVersion="14" />
  8.      uses-permission android:name="introduction.android.permission.USE_MYDB" />
  9.     application
  10.         android:allowBackup="true"
  11.         android:icon="@mipmap/ic_launcher"
  12.         android:label="@string/app_name"
  13.         android:roundIcon="@mipmap/ic_launcher_round"
  14.         android:supportsRtl="true"
  15.         android:theme="@style/AppTheme">
  16.         provider
  17.             android:name="MyDbProvider"
  18.             android:authorities="introduction.android.mydbdemo.MyFriendsDB" />
  19.         activity android:name=".MainActivity">
  20.             <intent-filter>
  21.                 action android:name="android.intent.action.MAIN" />
  22.                 category android:name="android.intent.category.LAUNCHER" />
  23.             </intent-filter>
  24.         /activity>
  25.     /application>
  26.  
  27. </manifest>
该文件通过如下代码:

<provider android:name="MyDbProvider" android:authorities="introduction.android.mydbdemo.MyFriendsDB" />

指明该 ContentProvider 名为 MyDbProvider,该 ContentProvider 的 Authority 为 introduction.android.mydbdemo.myfriendsdb。

通过如下代码:

<uses-permission android:name="introduction.android.permission.USE_MYDB"/>

指明该 ContentProvider 的权限为 introduction.android.permission.USE_MYDB,只有具有该权限的应用程序才可以访问该 ContentProvider。