Android自定义Content Provider实例

来源:互联网 发布:淘宝转淘口令api 编辑:程序博客网 时间:2024/06/04 18:27
我们大家都知道让自己的数据和其它应用程序共享有两种方式:创建自己的Content Provider (即继承自Content Provider的子类) 或者是将自己的数据添加到已有的Content Provider中去,后者需要保证现有的Content Provider和自己的数据类型相同并且具有该 Content Provider的写入的权限。 

     如果需要创建一个Content Provider,则需要进行的工作主要分为以下3个步骤。 

    (1)  建立数据的存储系统 

      数据的存储系统可以由开发人员任意决定,一般来讲,大多数的Content Provider都通过Android的文件存储系统或SQLite 数据库建立自己的数据存储系统。 

     (2)扩展 ContentProvider类 

       开发一个继承自ContentProvider类的 子类代码来扩展 ContentProvider类,在这个步骤主要的工作是将要共享的数据包装并以ContentResolver 和 Cursor对象能够访问到的形式对外展示。具体来说需要实现ContentProvider 类中的6个抽象方法。 

       Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):将查询的数据以Cursor 对象的形式返回。 

        Uri insert(Uri uri, ContentValues values):向 Content Provider中插入新数据记录,ContentValues 为数据记录的列名和列值映射。 

        int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):更新Content Provider中已存在的数据记录。 

        int delete(Uri uri, String selection, String[] selectionArgs):从Content Provider中删除数据记录。 

        String getType(Uri uri):返回Content Provider中的数据( MIME )类型。 

        boolean onCreate():当 Content Provider 启动时被调用。 

        以上方法将会在ContentResolver 对象中调用,所以很好地实现这些抽象方法会为ContentResolver提供一个完善的外部接口。除了实现抽象方法外,还可以做一些提高可用性的工作。 

        定义一个 URI 类型的静态常量,命名为CONTENT_URI。 必须为该常量对象定义一个唯一的URI字符串,一般的做法是将 ContentProvider子类的全称类名作为URI字符串,如: 
"content://wyf.wpf.MyProvider"。 

        定义每个字段的列名,如果采用的数据库存储系统为SQLite 数据库,数据表列名可以采用数据库中表的列名。不管数据表中有没有其他的唯一标识一个记录的字段,都应该定义一个"_id"字段 来唯一标识一个记录。模式使用 "INTEGER PRIMARY KEY AUTOINCREMENT" 自动更新 一般将这些列名字符串定义为静态常量, 如"_id"字段名定义为一个名为"_ID"  值为 "_id" 的静态字符串对象。 
     
       (3)在应用程序的AdnroidManifest.xml 文件中声明Content Provider组件。 

创建好一个Content Provider必须要在应用程序的AndroidManifest.xml 中进行声明,否则该Content Provider对于 Android系统将是不可见的。如果有一个名为MyProvider的类扩展了 ContentProvider类,声明该组件的代码如下: 
Xml代码  收藏代码
  1. <provider name="wyf.wpf.MyProvider"  
  2.                  authorities="wyf.wpf.myprovider"  
  3.                  ...../>   <!-- 为<provider>标记添加name、authorities属性-->  

     其中name属性为ContentProvider 子类的全称类名,authorities 属性唯一标识了一个ContentProvider。还可以通过 setReadPermission() 和 setWritePermission() 来设置其操作权限。当然也可以再上面的 xml中加入 android:readPermission 或者 android: writePermission属性来控制其权限。 

  注意:因为ContentProvider可能被不同的进程和线程调用,所以这些方法必须是线程安全的。
 

   下边是一个例子修改了 SDK 中的 Notes例子。首先创建 ContentProvider 的 CONTENT_URI 和 一些字段数据,字段类可以继承自BaseColumns类,它包括了一些基本的字段,比如:_id等  代码如下: 

NotePad类 
Java代码  收藏代码
  1. package xiaohang.zhimeng;  
  2.   
  3. import android.net.Uri;  
  4. import android.provider.BaseColumns;  
  5.   
  6. public class NotePad {  
  7.     //ContentProvider的uri  
  8.     public static final String AUTHORITY = "com.xh.google.provider.NotePad";  
  9.       
  10.     private NotePad(){}  
  11.       
  12.     //定义基本字段   实现BaseColumns 这个接口里边已经定义了"_id"字段所以这里不用定义了  
  13.     public static final class Notes implements BaseColumns{  
  14.         private Notes(){}  
  15.              
  16.         //Uri.parse 方法根据指定字符串创建一个 Uri 对象  
  17.         public static final Uri     CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes");  
  18.           
  19.         //新的MIME类型-多个  
  20.         public static final String  CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.note";  
  21.           
  22.         //新的MIME类型-单个  
  23.         public static final String  CONTENT_ITME_TYPE  = "vnd.android.cursor.item/vnd.google.note";  
  24.           
  25.         public static final String  DEFAULT_SORT_ORDER = "modified DESC";  
  26.           
  27.         //字段  
  28.         public static final String  TITLE              = "title";  
  29.         public static final String  NOTE               = "note";  
  30.         public static final String  CREATEDDATE        = "created";  
  31.         public static final String  MODIFIEDDATE       = "modified";  
  32.     }  
  33. }  


     然后我们需要来创建自己的 ContentProvider 类的 NotePadProvider,它包括了查询、添加、删除、更新等操作以及打开和创建数据库,代码如下: 

NotePadProvider 类 
Java代码  收藏代码
  1. package xiaohang.zhimeng;  
  2.   
  3. import java.util.HashMap;  
  4. import xiaohang.zhimeng.NotePad.Notes;  
  5. import android.content.ContentProvider;  
  6. import android.content.ContentUris;  
  7. import android.content.ContentValues;  
  8. import android.content.Context;  
  9. import android.content.UriMatcher;  
  10. import android.content.res.Resources;  
  11. import android.database.Cursor;  
  12. import android.database.SQLException;  
  13. import android.database.sqlite.SQLiteDatabase;  
  14. import android.database.sqlite.SQLiteOpenHelper;  
  15. import android.database.sqlite.SQLiteQueryBuilder;  
  16. import android.net.Uri;  
  17. import android.text.TextUtils;  
  18.   
  19. public class NotePadProvider extends ContentProvider{  
  20.       
  21.     private static final String            TAG = "NotePadProvider";  
  22.     //数据库名  
  23.     private static final String            DATABASE_NAME = "note_pad.db";  
  24.     private static final int               DATABASE_VERSION = 2;  
  25.     //表名  
  26.     private static final String            NOTES_TABLE_NAME = "notes";  
  27.     private static HashMap<String, String> sNotesProjectionMap;  
  28.     private static final int               NOTES = 1;  
  29.     private static final int               NOTE_ID = 2;  
  30.     private static final UriMatcher        sUriMatcher;  
  31.     private DatabaseHelper mOpenHelper;  
  32.     //创建表SQL语句  
  33.     private static final String            CREATE_TABLE="CREATE TABLE"  
  34.                                                         + NOTES_TABLE_NAME  
  35.                                                         + "(" + Notes._ID  
  36.                                                         + "INTEGER PRIMARY KEY,"  
  37.                                                         + Notes.TITLE  
  38.                                                         + " TEXT,"  
  39.                                                         + Notes.NOTE  
  40.                                                         + " TEXT,"  
  41.                                                         + Notes.CREATEDDATE  
  42.                                                         + " INTEGER,"  
  43.                                                         + Notes.MODIFIEDDATE  
  44.                                                         + " INTEGER" + "); ";  
  45.       
  46.     static{  
  47.         sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);  
  48.         sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);  
  49.         sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);  
  50.           
  51.         sNotesProjectionMap = new HashMap<String, String>();  
  52.         sNotesProjectionMap.put(Notes._ID, Notes._ID);  
  53.         sNotesProjectionMap.put(Notes.TITLE, Notes.TITLE);  
  54.         sNotesProjectionMap.put(Notes.NOTE, Notes.NOTE);  
  55.         sNotesProjectionMap.put(Notes.CREATEDDATE, Notes.CREATEDDATE);  
  56.         sNotesProjectionMap.put(Notes.MODIFIEDDATE, Notes.MODIFIEDDATE);  
  57.   
  58.     }  
  59.       
  60.     private static class DatabaseHelper extends SQLiteOpenHelper{  
  61.         //构造函数-创建数据库  
  62.         DatabaseHelper(Context context){  
  63.             super(context, DATABASE_NAME, null, DATABASE_VERSION);  
  64.         }  
  65.           
  66.         //创建表  
  67.         @Override  
  68.         public void onCreate(SQLiteDatabase db) {  
  69.             db.execSQL(CREATE_TABLE);  
  70.         }  
  71.           
  72.         //更新数据库  
  73.         @Override  
  74.         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
  75.             db.execSQL("DROP TABLE IF EXISTS notes");  
  76.             onCreate(db);  
  77.         }  
  78.     }  
  79.   
  80.     //删除数据  
  81.     @Override  
  82.     public int delete(Uri uri, String selection, String[] selectionArgs) {  
  83.         SQLiteDatabase db = mOpenHelper.getWritableDatabase();  
  84.         int count;  
  85.         switch (sUriMatcher.match(uri)) {  
  86.         case NOTES:  
  87.             count = db.delete(NOTES_TABLE_NAME, selection, selectionArgs);  
  88.             break;  
  89.               
  90.         case NOTE_ID:  
  91.             String noteId = uri.getPathSegments().get(1);  
  92.             count = db.delete(NOTES_TABLE_NAME, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);  
  93.             break;  
  94.               
  95.         default:  
  96.             throw new IllegalArgumentException("Unnown URI" + uri);  
  97.         }  
  98.         getContext().getContentResolver().notifyChange(uri, null);  
  99.         return count;  
  100.     }  
  101.     //如果有自定类型,必须实现该方法  
  102.     @Override  
  103.     public String getType(Uri uri) {  
  104.         switch (sUriMatcher.match(uri)) {  
  105.         case NOTES:  
  106.             return Notes.CONTENT_TYPE;  
  107.   
  108.         case NOTE_ID:  
  109.             return Notes.CONTENT_ITME_TYPE;  
  110.               
  111.         default:  
  112.             throw new IllegalArgumentException("Unknown URI " + uri);  
  113.         }  
  114.     }  
  115.   
  116.     //插入数据库  
  117.     @Override  
  118.     public Uri insert(Uri uri, ContentValues initialValues) {  
  119.         if (sUriMatcher.match(uri) != NOTES) {  
  120.             throw new IllegalArgumentException("Unknown URI " + uri);  
  121.         }  
  122.         ContentValues values;  
  123.         if (initialValues != null) {  
  124.             values = new ContentValues(initialValues);  
  125.         }else {  
  126.             values = new ContentValues();  
  127.         }  
  128.         //返回以毫秒为单位的系统当前时间  
  129.         Long now = Long.valueOf(java.lang.System.currentTimeMillis());  
  130.         /** 
  131.          * contaisKey()我的理解就是判断传进来的那个ContentValues有没有相应的列值 
  132.          * 因为我们的一个ContentValues对象 对应一条数据库的记录 
  133.          * */  
  134.         if (values.containsKey(NotePad.Notes.CREATEDDATE) == false) {  
  135.             values.put(NotePad.Notes.CREATEDDATE, now);  
  136.         }  
  137.         if (values.containsKey(NotePad.Notes.MODIFIEDDATE) == false) {  
  138.             values.put(NotePad.Notes.MODIFIEDDATE, now);  
  139.         }  
  140.         if (values.containsKey(NotePad.Notes.TITLE) == false) {  
  141.             //返回一个全局共享的资源对象  
  142.             Resources r = Resources.getSystem();  
  143.             values.put(NotePad.Notes.TITLE, r.getString(android.R.string.unknownName));  
  144.         }  
  145.         if (values.containsKey(NotePad.Notes.NOTE) == false) {  
  146.             values.put(NotePad.Notes.NOTE, "");  
  147.         }  
  148.         SQLiteDatabase db = mOpenHelper.getWritableDatabase();  
  149.         long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values);  
  150.         if (rowId > 0) {  
  151.             Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId);  
  152.             getContext().getContentResolver().notifyChange(noteUri, null);  
  153.             return noteUri;  
  154.         }  
  155.         throw new SQLException("Failed to insert row into" + uri);  
  156.     }  
  157.       
  158.     //当Content Provider启动时被调用  
  159.     @Override  
  160.     public boolean onCreate() {  
  161.         mOpenHelper = new DatabaseHelper(getContext());  
  162.         return true;  
  163.     }  
  164.       
  165.     //查询操作  将查询的数据以 Cursor 对象的形式返回  
  166.     @Override  
  167.     public Cursor query(Uri uri, String[] projection, String selection,  
  168.             String[] selectionArgs, String sortOrder) {  
  169.         SQLiteQueryBuilder qb = new SQLiteQueryBuilder();  
  170.         switch (sUriMatcher.match(uri)) {  
  171.         case NOTES:  
  172.             qb.setTables(NOTES_TABLE_NAME);  
  173.             qb.setProjectionMap(sNotesProjectionMap);  
  174.             break;  
  175.               
  176.         case NOTE_ID:  
  177.             qb.setTables(NOTES_TABLE_NAME);  
  178.             qb.setProjectionMap(sNotesProjectionMap);  
  179.             qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1));  
  180.             break;  
  181.               
  182.         default:  
  183.             throw new IllegalArgumentException("Unknown URI " + uri);  
  184.         }  
  185.         String orderBy;  
  186.         //返回true,如果字符串为空或0长度  
  187.         if (TextUtils.isEmpty(sortOrder)) {  
  188.             orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;  
  189.         }else {  
  190.             orderBy = sortOrder;  
  191.         }  
  192.         SQLiteDatabase db = mOpenHelper.getReadableDatabase();  
  193.         Cursor c = qb.query(db, projection, selection, selectionArgs, nullnull, orderBy);  
  194.         //用来为Cursor对象注册一个观察数据变化的URI  
  195.         c.setNotificationUri(getContext().getContentResolver(), uri);  
  196.         return c;  
  197.     }  
  198.   
  199.     //更新数据  
  200.     @Override  
  201.     public int update(Uri uri, ContentValues values, String selection,  
  202.             String[] selectionArgs) {  
  203.         SQLiteDatabase db = mOpenHelper.getWritableDatabase();  
  204.         int count;  
  205.         switch (sUriMatcher.match(uri)) {  
  206.         case NOTES:  
  207.             count = db.update(NOTES_TABLE_NAME, values, selection, selectionArgs);  
  208.             break;  
  209.           
  210.         case NOTE_ID:  
  211.             String noteId = uri.getPathSegments().get(1);  
  212.             count = db.update(NOTES_TABLE_NAME, values, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);  
  213.             break;  
  214.               
  215.         default:  
  216.             throw new IllegalArgumentException("Unknow URI " + uri);  
  217.         }  
  218.           
  219.         return count;  
  220.     }  
  221. }  

    
     下面我们要来创建一个Activity类,首先向其中插入两个数据,然后通过Toast来显示数据库中的数据。 运行效果如下: 

 

 

代码 Activity01 类 
Java代码  收藏代码
  1. package xiaohang.zhimeng;  
  2.   
  3. import android.app.Activity;  
  4. import android.content.ContentValues;  
  5. import android.database.Cursor;  
  6. import android.net.Uri;  
  7. import android.os.Bundle;  
  8. import android.view.Gravity;  
  9. import android.widget.Toast;  
  10.   
  11. public class Activity01 extends Activity {  
  12.     @Override  
  13.     public void onCreate(Bundle savedInstanceState) {  
  14.         super.onCreate(savedInstanceState);  
  15.         setContentView(R.layout.main);  
  16.           
  17.         /*插入数据*/  
  18.         ContentValues values = new ContentValues();  
  19.         values.put(NotePad.Notes.TITLE, "title1");  
  20.         values.put(NotePad.Notes.NOTE, "NOTENOTE1");  
  21.         getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);  
  22.           
  23.         values.clear();  
  24.         values.put(NotePad.Notes.TITLE, "title2");  
  25.         values.put(NotePad.Notes.NOTE, "NOTENOTE2");  
  26.         getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);  
  27.         //显示  
  28.         displayNote();  
  29.     }  
  30.       
  31.     private void displayNote(){  
  32.         String columns[] = new String[] { NotePad.Notes._ID,  
  33.                                           NotePad.Notes.TITLE,  
  34.                                           NotePad.Notes.NOTE,  
  35.                                           NotePad.Notes.CREATEDDATE,  
  36.                                           NotePad.Notes.MODIFIEDDATE};  
  37.           
  38.         Uri myUri = NotePad.Notes.CONTENT_URI;  
  39.         Cursor cur = managedQuery(myUri, columns, nullnullnull);  
  40.         if (cur.moveToFirst()) {  
  41.             String id = null;  
  42.             String titile = null;  
  43.             do {  
  44.                 id = cur.getString(cur.getColumnIndex(NotePad.Notes._ID));  
  45.                 titile = cur.getString(cur.getColumnIndex(NotePad.Notes.TITLE));  
  46.                 Toast toast = Toast.makeText(this"TITILE:"+id + "\t" + "NOTE:" + titile, Toast.LENGTH_LONG);  
  47.                 toast.setGravity(Gravity.TOP|Gravity.CENTER, 040);  
  48.                 toast.show();  
  49.             } while (cur.moveToNext());  
  50.         }  
  51.     }  
  52. }  


  最后不要忘记在AndroidManifest.xml文件中声明我们使用的ContentProvider,下面是我的 
AndroidManifest.xml文件 
Xml代码  收藏代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="xiaohang.zhimeng" android:versionCode="1"  
  4.     android:versionName="1.0">  
  5.     <application android:icon="@drawable/icon"  
  6.         android:label="@string/app_name">  
  7.         <provider android:name="NotePadProvider"  
  8.             android:authorities="com.xh.google.provider.NotePad" />  
  9.         <activity android:name=".Activity01"  
  10.             android:label="@string/app_name">  
  11.             <intent-filter>  
  12.                 <action android:name="android.intent.action.MAIN" />  
  13.                 <category  
  14.                     android:name="android.intent.category.LAUNCHER" />  
  15.             </intent-filter>  
  16.             <intent-filter>  
  17.                 <data  
  18.                     android:mimeType="vnd.android.cursor.dir/vnd.google.note" />  
  19.             </intent-filter>  
  20.             <intent-filter>  
  21.                 <data  
  22.                     android:mimeType="vnd.android.cursor.item/vnd.google.note" />  
  23.             </intent-filter>  
  24.         </activity>  
  25.     </application>  
  26.     <uses-sdk android:minSdkVersion="5" />  
  27.   
  28. </manifest>  
0 0