数据共享ContentProvider,ContentResolver

本文深入讲解了Android中数据共享机制ContentProvider与ContentResolver的工作原理,包括如何定义自定义ContentProvider,实现数据的增删改查操作,以及如何通过ContentResolver进行跨应用数据访问。

三、数据存储3:数据共享ContentProvider,ContentResolver

         把这篇博客补一下,之前学习一直想整理一下,但是总不知道如何下手,因为这块内容与之前web开发中的思路有一定的差异,自己所以就稍微晚了1周来补充这篇博客。

         之前介绍过了数据存储操作的方式可知,每个程序都是线程控制,并且数据无法共享,而ContentProvider来解决这个问题,ContentProvider是所有应用程序之间数据存储与检索的一个桥梁,他的作用就是使得各个程序之间实现数据共享。

         可以把ContentProvider理解为一种特殊的存储数据的类型,因为ContentProvider是个抽象类,继承自该类必须实现:getType,insert,delete,update,query方法,所以它提供了一套上述接口来获取,操作数据。

 

         就像我们学习web开发刚接触Model1的MVC时,数据层方面实现了针对实体的增删改查,但是在业务层方面最好封装一个数据操作的Service,这样的话就避免了业务层直接操作数据层,而把这个工作交给对应的Service的实现,更好的管理。这里就引出了ContentResolver,它的作用就可以理解为对应Service的实现来操作对应ContentProvider。

ContentResolver对象的获取可以通过getContentResolver()方法来取得

      

         这里需要说明的是,每个ContentProvider都会对外提供一个公共的URI(包装成Uri对象),如果应用程序有数据需要共享,就需要使用ContentProvider为这些数据定义一个URI,然后其他应用程序就可以通过ContentProvider传入这个URI来对数据进行操作。URI由3个部分组成:“content://”、数据的路径、标示ID(可选)。如:

        content://media/internal/images   这个URI返回设备上存储的所有图片

        content://contacts/people/5       联系人信息中ID为5的联系人记录

        content://contacts:/people/       这个URI返回设备上得所有联系人信息。

 

当然android.provider包下也提供了一些辅助类来达到上述效果如:

  1. Uri person = ContentUris.withAppendedId(People.CONTENT_URI , 5);  

 

       这里个人认为有点像OSGI中,Serivice的注册,用一个标示Id(这里是URI)来标示当前系统提供了哪些服务(这里是共享数据),通过Id获取了对应Service然后进行操作。而ContentResolver都把URI作为其参数,用来表明该ContentResolver在操作哪个ContentProvider。

  1. getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);  

      如上面这行代码就是ContentResolver操作了对应Notes的URI,后面参数values就是数据值。

 

【扩展学习】:如果要是自己创建自己的Contentprovider,并且数据类型是当前不存在的,则需要定义自己的返回列,同时也要定义对应的一种新的MIME类型,可以这样理解:当前共享数据中没有的类型需要进行配置与定义,才能使用,不然无法识别。

        

 而这里我们用SDK改写的的实例Notes进行测试,上述所有MIME类型以及返回列的定义都在NotePad类:

  1. public class NotePad {  
  2.     public static final String AUTHORITY = "com.google.provider.NotePad";   //ContentProvider的uri  
  3.   
  4.     public NotePad(){}  
  5.       
  6.     //定义基本字段  
  7.     public static final class Notes implements BaseColumns{  
  8.         public Notes(){}  
  9.           
  10.         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes");  
  11.           
  12.         //新的MIME类型-多个  
  13.         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.note";  
  14.           
  15.         // 新的MIME类型-单个  
  16.         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.note";  
  17.           
  18.         public static final String  DEFAULT_SORT_ORDER  = "modified DESC";  
  19.           
  20.         //字段  
  21.         public static final String  TITLE               = "title";  
  22.         public static final String  NOTE                = "note";  
  23.         public static final String  CREATEDDATE         = "created";  
  24.         public static final String  MODIFIEDDATE        = "modified";  
  25.     }  
  26. }  

同时对应的AndroidManifest.xml文件中需要配置provider

  1. <provider android:name="NotePadProvider" android:authorities="com.google.provider.NotePad"/>  


 

而NotePadProvider类:

  1. public class NotePadProvider extends ContentProvider{  
  2.     private static final String             TAG              = "NotePadProvider";  
  3.     // 数据库名  
  4.     private static final String             DATABASE_NAME       = "note_pad.db";  
  5.     private static final int                DATABASE_VERSION    = 2;  
  6.     // 表名  
  7.     private static final String             NOTES_TABLE_NAME    = "notes";  
  8.     private static HashMap<String, String>    sNotesProjectionMap;  
  9.     private static final int                NOTES               = 1;  
  10.     private static final int                NOTE_ID             = 2;  
  11.     private static final UriMatcher         sUriMatcher;  
  12.     private DatabaseHelper  mOpenHelper;  
  13.     //创建表SQL语句  
  14.     private static final String             CREATE_TABLE="CREATE TABLE "   
  15.                                                         + NOTES_TABLE_NAME   
  16.                                                         + " (" + Notes._ID   
  17.                                                         + " INTEGER PRIMARY KEY,"   
  18.                                                         + Notes.TITLE   
  19.                                                         + " TEXT,"   
  20.                                                         + Notes.NOTE   
  21.                                                         + " TEXT,"  
  22.                                                         + Notes.CREATEDDATE   
  23.                                                         + " INTEGER,"   
  24.                                                         + Notes.MODIFIEDDATE   
  25.                                                         + " INTEGER" + ");";  
  26.       
  27.     static{  
  28.         sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);  
  29.         sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);  
  30.         sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);  
  31.   
  32.         sNotesProjectionMap = new HashMap<String, String>();  
  33.         sNotesProjectionMap.put(Notes._ID, Notes._ID);  
  34.         sNotesProjectionMap.put(Notes.TITLE, Notes.TITLE);  
  35.         sNotesProjectionMap.put(Notes.NOTE, Notes.NOTE);  
  36.         sNotesProjectionMap.put(Notes.CREATEDDATE, Notes.CREATEDDATE);  
  37.         sNotesProjectionMap.put(Notes.MODIFIEDDATE, Notes.MODIFIEDDATE);  
  38.     }  
  39.     private static class DatabaseHelper extends SQLiteOpenHelper{  
  40.         //构造函数-创建数据库  
  41.         DatabaseHelper(Context context){  
  42.             super(context, DATABASE_NAME, null, DATABASE_VERSION);  
  43.         }  
  44.         //创建表  
  45.         @Override  
  46.         public void onCreate(SQLiteDatabase db){  
  47.             db.execSQL(CREATE_TABLE);  
  48.         }  
  49.         //更新数据库  
  50.         @Override  
  51.         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){  
  52.             db.execSQL("DROP TABLE IF EXISTS notes");  
  53.             onCreate(db);  
  54.         }  
  55.     }  
  56.     @Override  
  57.     public boolean onCreate(){  
  58.         mOpenHelper = new DatabaseHelper(getContext());  
  59.         return true;  
  60.     }  
  61.     @Override  
  62.     //查询操作  
  63.     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder){  
  64.         SQLiteQueryBuilder qb = new SQLiteQueryBuilder();  
  65.         switch (sUriMatcher.match(uri)){  
  66.             case NOTES:  
  67.                 qb.setTables(NOTES_TABLE_NAME);  
  68.                 qb.setProjectionMap(sNotesProjectionMap);  
  69.                 break;  
  70.   
  71.             case NOTE_ID:  
  72.                 qb.setTables(NOTES_TABLE_NAME);  
  73.                 qb.setProjectionMap(sNotesProjectionMap);  
  74.                 qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1));  
  75.                 break;  
  76.   
  77.             default:  
  78.                 throw new IllegalArgumentException("Unknown URI " + uri);  
  79.         }  
  80.         String orderBy;  
  81.         if (TextUtils.isEmpty(sortOrder)){  
  82.             orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;  
  83.         }else{  
  84.             orderBy = sortOrder;  
  85.         }  
  86.         SQLiteDatabase db = mOpenHelper.getReadableDatabase();  
  87.         Cursor c = qb.query(db, projection, selection, selectionArgs, nullnull, orderBy);  
  88.         c.setNotificationUri(getContext().getContentResolver(), uri);  
  89.         return c;  
  90.     }  
  91.     @Override  
  92.     // 如果有自定义类型,必须实现该方法  
  93.     public String getType(Uri uri){  
  94.         switch (sUriMatcher.match(uri)){  
  95.             case NOTES:  
  96.                 return Notes.CONTENT_TYPE;  
  97.   
  98.             case NOTE_ID:  
  99.                 return Notes.CONTENT_ITEM_TYPE;  
  100.   
  101.             default:  
  102.                 throw new IllegalArgumentException("Unknown URI " + uri);  
  103.         }  
  104.     }  
  105.     @Override  
  106.     //插入数据库  
  107.     public Uri insert(Uri uri, ContentValues initialValues){  
  108.         if (sUriMatcher.match(uri) != NOTES){  
  109.             throw new IllegalArgumentException("Unknown URI " + uri);  
  110.         }  
  111.         ContentValues values;  
  112.         if (initialValues != null){  
  113.             values = new ContentValues(initialValues);  
  114.         }else{  
  115.             values = new ContentValues();  
  116.         }  
  117.         Long now = Long.valueOf(System.currentTimeMillis());  
  118.   
  119.         if (values.containsKey(NotePad.Notes.CREATEDDATE) == false){  
  120.             values.put(NotePad.Notes.CREATEDDATE, now);  
  121.         }  
  122.         if (values.containsKey(NotePad.Notes.MODIFIEDDATE) == false){  
  123.             values.put(NotePad.Notes.MODIFIEDDATE, now);  
  124.         }  
  125.         if (values.containsKey(NotePad.Notes.TITLE) == false){  
  126.             Resources r = Resources.getSystem();  
  127.             values.put(NotePad.Notes.TITLE, r.getString(android.R.string.untitled));  
  128.         }  
  129.         if (values.containsKey(NotePad.Notes.NOTE) == false){  
  130.             values.put(NotePad.Notes.NOTE, "");  
  131.         }  
  132.         SQLiteDatabase db = mOpenHelper.getWritableDatabase();  
  133.         long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values);  
  134.         if (rowId > 0){  
  135.             Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId);  
  136.             getContext().getContentResolver().notifyChange(noteUri, null);  
  137.             return noteUri;  
  138.         }  
  139.         throw new SQLException("Failed to insert row into " + uri);  
  140.     }  
  141.     @Override  
  142.     //删除数据  
  143.     public int delete(Uri uri, String where, String[] whereArgs){  
  144.         SQLiteDatabase db = mOpenHelper.getWritableDatabase();  
  145.         int count;  
  146.         switch (sUriMatcher.match(uri)){  
  147.             case NOTES:  
  148.                 count = db.delete(NOTES_TABLE_NAME, where, whereArgs);  
  149.                 break;  
  150.   
  151.             case NOTE_ID:  
  152.                 String noteId = uri.getPathSegments().get(1);  
  153.                 count = db.delete(NOTES_TABLE_NAME, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);  
  154.                 break;  
  155.   
  156.             default:  
  157.                 throw new IllegalArgumentException("Unknown URI " + uri);  
  158.         }  
  159.         getContext().getContentResolver().notifyChange(uri, null);  
  160.         return count;  
  161.     }  
  162.     @Override  
  163.     //更新数据  
  164.     public int update(Uri uri, ContentValues values, String where, String[] whereArgs){  
  165.         SQLiteDatabase db = mOpenHelper.getWritableDatabase();  
  166.         int count;  
  167.         switch (sUriMatcher.match(uri)){  
  168.             case NOTES:  
  169.                 count = db.update(NOTES_TABLE_NAME, values, where, whereArgs);  
  170.                 break;  
  171.   
  172.             case NOTE_ID:  
  173.                 String noteId = uri.getPathSegments().get(1);  
  174.                 count = db.update(NOTES_TABLE_NAME, values, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);  
  175.                 break;  
  176.   
  177.             default:  
  178.                 throw new IllegalArgumentException("Unknown URI " + uri);  
  179.         }  
  180.         getContext().getContentResolver().notifyChange(uri, null);  
  181.         return count;  
  182.     }  
  183. }  

 

最终操作的Activity类为:

 

  1. public class DataProviderActivity extends Activity {  
  2.     /** Called when the activity is first created. */  
  3.     @Override  
  4.     public void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(R.layout.main);  
  7.           
  8.         //插入数据  
  9.         ContentValues values = new ContentValues();  
  10.         values.put(NotePad.Notes.TITLE, "title1");  
  11.         values.put(NotePad.Notes.NOTE, "NoteNote1");  
  12.         getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);  
  13.           
  14.         values.clear();  
  15.         values.put(NotePad.Notes.TITLE, "title2");  
  16.         values.put(NotePad.Notes.NOTE, "NoteNote2");  
  17.         getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);  
  18.           
  19.         /* 显示 */  
  20.         displayNote();  
  21.     }  
  22.   
  23.     private void displayNote() {  
  24.         // TODO Auto-generated method stub  
  25.         String columns[] = new String[]{  
  26.                 NotePad.Notes._ID,  
  27.                 NotePad.Notes.TITLE,   
  28.                 NotePad.Notes.NOTE,   
  29.                 NotePad.Notes.CREATEDDATE,   
  30.                 NotePad.Notes.MODIFIEDDATE  
  31.         };  
  32.         Uri myUri = NotePad.Notes.CONTENT_URI;  
  33.         Cursor cursor = this.managedQuery(myUri, columns, nullnullnull);  
  34.         if (cursor.moveToFirst()) {  
  35.             String id = null;  
  36.             String title = null;  
  37.               
  38.             do{  
  39.                 id = cursor.getString(cursor.getColumnIndex(NotePad.Notes._ID));  
  40.                 title = cursor.getString(cursor.getColumnIndex(NotePad.Notes.TITLE));  
  41.                 Toast toast=Toast.makeText(this"TITLE:"+id + "NOTE:" + title, Toast.LENGTH_LONG);  
  42.                 toast.setGravity(Gravity.TOP|Gravity.CENTER, 040);  
  43.                 toast.show();  
  44.             }while(cursor.moveToNext());  
  45.         }  
  46.     }  
  47. }  


当然对应Activity类需要在配置文件里注册:

  1. <activity  
  2.             android:label="@string/app_name"  
  3.             android:name=".DataProviderActivity" >  
  4.             <intent-filter >  
  5.                 <action android:name="android.intent.action.MAIN" />  
  6.   
  7.                 <category android:name="android.intent.category.LAUNCHER" />  
  8.             </intent-filter>  
  9.             <intent-filter>  
  10.                 <data android:mimeType="vnd.android.cursor.dir/vnd.google.note"/>  
  11.             </intent-filter>  
  12.             <intent-filter>  
  13.                 <data android:mimeType="vnd.android.cursor.item/vnd.google.note"/>  
  14.             </intent-filter>  
  15.         </activity>  


这样实例运行效果:

 

对应的后台数据库内容:


到这里就完成本次数据共享的整理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值