一、字段部分
1 public class NotePadProvider extends ContentProvider { 2 3 private static final String TAG = "NotePadProvider"; 4 5 private static final String DATABASE_NAME = "note_pad.db"; 6 private static final int DATABASE_VERSION = 2; 7 private static final String NOTES_TABLE_NAME = "notes"; 8 9 private static HashMap<String, String> sNotesProjectionMap; 10 private static HashMap<String, String> sLiveFolderProjectionMap; 11 12 private static final int NOTES = 1; 13 private static final int NOTE_ID = 2; 14 private static final int LIVE_FOLDER_NOTES = 3; 15 16 private static final UriMatcher sUriMatcher;
5,DATABASE_NAME,表征你要使用的数据库名字,这里是note_pad.db,也就是说会在应用程序的数据文件夹里面生成一个名字为note_pad.db的Sqlite数据库文件。
二、静态初始化语句块部分
1 static { 2 sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 3 sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES); 4 sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID); 5 sUriMatcher.addURI(NotePad.AUTHORITY, "live_folders/notes", LIVE_FOLDER_NOTES); 6 7 sNotesProjectionMap = new HashMap<String, String>(); 8 sNotesProjectionMap.put(Notes._ID, Notes._ID); 9 sNotesProjectionMap.put(Notes.TITLE, Notes.TITLE); 10 sNotesProjectionMap.put(Notes.NOTE, Notes.NOTE); 11 sNotesProjectionMap.put(Notes.CREATED_DATE, Notes.CREATED_DATE); 12 sNotesProjectionMap.put(Notes.MODIFIED_DATE, Notes.MODIFIED_DATE); 13 14 // Support for Live Folders. 15 sLiveFolderProjectionMap = new HashMap<String, String>(); 16 sLiveFolderProjectionMap.put(LiveFolders._ID, Notes._ID + " AS " + 17 LiveFolders._ID); 18 sLiveFolderProjectionMap.put(LiveFolders.NAME, Notes.TITLE + " AS " + 19 LiveFolders.NAME); 20 // Add more columns here for more robust Live Folders. 21 }
三,一个SQLiteOpenHelper
1 /** 2 * This class helps open, create, and upgrade the database file. 3 */ 4 private static class DatabaseHelper extends SQLiteOpenHelper { 5 6 DatabaseHelper(Context context) { 7 super(context, DATABASE_NAME, null, DATABASE_VERSION); 8 } 9 10 @Override 11 public void onCreate(SQLiteDatabase db) { 12 db.execSQL("CREATE TABLE " + NOTES_TABLE_NAME + " (" 13 + Notes._ID + " INTEGER PRIMARY KEY," 14 + Notes.TITLE + " TEXT," 15 + Notes.NOTE + " TEXT," 16 + Notes.CREATED_DATE + " INTEGER," 17 + Notes.MODIFIED_DATE + " INTEGER" 18 + ");"); 19 } 20 21 @Override 22 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 23 Log.w(TAG, "Upgrading database from version " + oldVersion + " to " 24 + newVersion + ", which will destroy all old data"); 25 db.execSQL("DROP TABLE IF EXISTS notes"); 26 onCreate(db); 27 } 28 } 29 30 private DatabaseHelper mOpenHelper;这里实现了一个继承于SQLiteOpenHelper的DatabaseHelper内部类。这个类被封装在这里是因为这个ContentProvider本身是和数据库进行打交道的,所以需要一个SQLiteOpenHelper来处理相关关系。具体该类怎么用自己Google吧。
1 @Override 2 public boolean onCreate() { 3 mOpenHelper = new DatabaseHelper(getContext()); 4 return true; 5 }该方法用于对ContentProvider中的资源进行初始化,可以知道的是,这些处理是不可能在static语句块中实现的,因为会有一些要求,例如这里我们要传入一个Context实例给DataBaseHelper构造器,这在static语句块中是实现不了的。
1 @Override 2 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 3 String sortOrder) { 4 SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 5 qb.setTables(NOTES_TABLE_NAME); 6 7 switch (sUriMatcher.match(uri)) { 8 case NOTES: 9 qb.setProjectionMap(sNotesProjectionMap); 10 break; 11 12 case NOTE_ID: 13 qb.setProjectionMap(sNotesProjectionMap); 14 qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1)); 15 break; 16 17 case LIVE_FOLDER_NOTES: 18 qb.setProjectionMap(sLiveFolderProjectionMap); 19 break; 20 21 default: 22 throw new IllegalArgumentException("Unknown URI " + uri); 23 } 24 25 // If no sort order is specified use the default 26 String orderBy; 27 if (TextUtils.isEmpty(sortOrder)) { 28 orderBy = NotePad.Notes.DEFAULT_SORT_ORDER; 29 } else { 30 orderBy = sortOrder; 31 } 32 33 // Get the database and run the query 34 SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 35 Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy); 36 37 // Tell the cursor what uri to watch, so it knows when its source data changes 38 c.setNotificationUri(getContext().getContentResolver(), uri); 39 return c; 40 }
1 @Override 2 public String getType(Uri uri) { 3 switch (sUriMatcher.match(uri)) { 4 case NOTES: 5 case LIVE_FOLDER_NOTES: 6 return Notes.CONTENT_TYPE; 7 8 case NOTE_ID: 9 return Notes.CONTENT_ITEM_TYPE; 10 11 default: 12 throw new IllegalArgumentException("Unknown URI " + uri); 13 } 14 }
关于getType使用提示:
<intent-filter android:label="@string/resolve_edit">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.EDIT" />
<action android:name="com.android.notepad.action.EDIT_NOTE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
</intent-filter>
我們很容易看出action和category是很容易匹配的,而我們傳的Uri的數據怎麼匹配呢,這時系統就會去調用你定義的ContentProvider中的getType,取得相關的返回值來和上面的data串進行匹配,當然getType的返回結果你是需要自己去定義的。
但在程序中你也可以自己知道data的類型,就直接匹配了:intent.setType(type);
1 @Override 2 public Uri insert(Uri uri, ContentValues initialValues) { 3 // Validate the requested uri 4 if (sUriMatcher.match(uri) != NOTES) { 5 throw new IllegalArgumentException("Unknown URI " + uri); 6 } 7 8 ContentValues values; 9 if (initialValues != null) { 10 values = new ContentValues(initialValues); 11 } else { 12 values = new ContentValues(); 13 } 14 15 Long now = Long.valueOf(System.currentTimeMillis()); 16 17 // Make sure that the fields are all set 18 if (values.containsKey(NotePad.Notes.CREATED_DATE) == false) { 19 values.put(NotePad.Notes.CREATED_DATE, now); 20 } 21 22 if (values.containsKey(NotePad.Notes.MODIFIED_DATE) == false) { 23 values.put(NotePad.Notes.MODIFIED_DATE, now); 24 } 25 26 if (values.containsKey(NotePad.Notes.TITLE) == false) { 27 Resources r = Resources.getSystem(); 28 values.put(NotePad.Notes.TITLE, r.getString(android.R.string.untitled)); 29 } 30 31 if (values.containsKey(NotePad.Notes.NOTE) == false) { 32 values.put(NotePad.Notes.NOTE, ""); 33 } 34 35 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 36 long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values); 37 if (rowId > 0) { 38 Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId); 39 getContext().getContentResolver().notifyChange(noteUri, null); 40 return noteUri; 41 } 42 43 throw new SQLException("Failed to insert row into " + uri); 44 }
1 @Override 2 public int delete(Uri uri, String where, String[] whereArgs) { 3 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 4 int count; 5 switch (sUriMatcher.match(uri)) { 6 case NOTES: 7 count = db.delete(NOTES_TABLE_NAME, where, whereArgs); 8 break; 9 10 case NOTE_ID: 11 String noteId = uri.getPathSegments().get(1); 12 count = db.delete(NOTES_TABLE_NAME, Notes._ID + "=" + noteId 13 + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs); 14 break; 15 16 default: 17 throw new IllegalArgumentException("Unknown URI " + uri); 18 } 19 20 getContext().getContentResolver().notifyChange(uri, null); 21 return count; 22 } 23 24 @Override 25 public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { 26 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 27 int count; 28 switch (sUriMatcher.match(uri)) { 29 case NOTES: 30 count = db.update(NOTES_TABLE_NAME, values, where, whereArgs); 31 break; 32 33 case NOTE_ID: 34 String noteId = uri.getPathSegments().get(1); 35 count = db.update(NOTES_TABLE_NAME, values, Notes._ID + "=" + noteId 36 + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs); 37 break; 38 39 default: 40 throw new IllegalArgumentException("Unknown URI " + uri); 41 } 42 43 getContext().getContentResolver().notifyChange(uri, null); 44 return count; 45 } 46 }
四,小结
分为A,B,C,D 4个部分:
A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;"content://"
B:URI的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它 必须是一个完整的、小写的 类名。这个标识在 元素的 authorities属性中说明:一般是定义该ContentProvider的包. 类的名称 ;"content://com.android.calendar" (系统日历的URI)
C:路径,URI下的某一个Item,就像网站一样,主网页下包含很多小网页。这里通俗的讲就是你要操作的数据库中表的名 字,或者你也可以自己定义,记得在使用的时候保持一致就ok了;"content://com.android.calendar/calendars"
D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部; "content://com.android.calendar/calendars/#" #表示数据id(#代表任意数字)
"content://com.android.calendar/calendars/*" *来匹配任意文本
ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
withAppendedId(uri, id)用于为路径加上ID部分
parseId(uri)方法用于从路径中获取ID部分
一是:按名字查询;二是:多表查询。
我的理解:其实ContentProvider的机制很随意,它就类似于一个服务器一样,你把uri传来,只要按照特定的方式,它就能给你特定的功能,我觉得这个机制自由又方便。
其实这两个功能主要通过修改query就可以,完整的ContentProvider代码如下:
package com.ianc.lilyprovider; import android.content.ContentProvider; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import android.util.Log; public class LilyProvider extends ContentProvider { final static String TABLE_NAME = "customer"; final static String PRODUCT_TABLE = "shoplist"; private static final String DATABASE_NAME = "lily.db"; private static String AUTHORITY = "com.ianc.lilyprovider"; private static final int DATABASE_VERSION = 1; DatabaseHelper mDbHelper; static UriMatcher sUriMatcher; private static final int USER = 1; private static final int USER_NAME = 2; private static final int MULITABLE = 3; private static final int SHOPLIST = 4; static{ sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); sUriMatcher.addURI(AUTHORITY, TABLE_NAME, USER); sUriMatcher.addURI(AUTHORITY, PRODUCT_TABLE, SHOPLIST); sUriMatcher.addURI(AUTHORITY, TABLE_NAME+"/"+LilyUser.UserColumns.NAME+"/*", USER_NAME);//search special user by name sUriMatcher.addURI(AUTHORITY, TABLE_NAME+"/*", MULITABLE); } class DatabaseHelper extends SQLiteOpenHelper { public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { Log.i("lily","LilyProvider-->DatabaseHelper-->onCreate"); db.execSQL("Create table " + TABLE_NAME + "( " + LilyUser.UserColumns._ID+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + LilyUser.UserColumns._COUNT + " INTEGER,"+ LilyUser.UserColumns.NAME + " TEXT," + LilyUser.UserColumns.PASSWORD +" TEXT" + ");"); db.execSQL("Create table " + PRODUCT_TABLE + "( " + LilyUser.ShopListColumns._ID+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + LilyUser.ShopListColumns._COUNT + " INTEGER,"+ LilyUser.ShopListColumns.USER_ID+" INTEGER,"+ LilyUser.ShopListColumns.PRODUCT + " TEXT," + LilyUser.ShopListColumns.DATE +" TEXT" + ");"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.i("lily","LilyProvider-->DatabaseHelper-->onUpgrade"); db.execSQL("DROP TABLE IF EXISTS "+TABLE_NAME+";"); db.execSQL("DROP TABLE IF EXISTS "+PRODUCT_TABLE+";"); onCreate(db); } } @Override public int delete(Uri arg0, String arg1, String[] arg2) { Log.i("lily","LilyProvider-->delete"); SQLiteDatabase db = mDbHelper.getWritableDatabase(); int rownum = db.delete(TABLE_NAME, arg1, arg2); return rownum; } @Override public String getType(Uri uri) { Log.i("lily","LilyProvider-->getType"); return null; } @Override public Uri insert(Uri uri, ContentValues values) { Log.i("lily","LilyProvider-->insert"); if (sUriMatcher.match(uri) == USER){ SQLiteDatabase db = mDbHelper.getWritableDatabase(); db.insert(TABLE_NAME, null, values); } else if (sUriMatcher.match(uri) == SHOPLIST){ SQLiteDatabase db = mDbHelper.getWritableDatabase(); db.insert(PRODUCT_TABLE, null, values); } return null; } @Override public boolean onCreate() { Log.i("lily","LilyProvider-->onCreate"); mDbHelper = new DatabaseHelper(this.getContext()); return false; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Log.i("lily","LilyProvider-->query"); Log.i("lily","uri = "+uri); Log.i("lily","sUriMatcher.match(uri)="+sUriMatcher.match(uri)); Cursor c = null; if (sUriMatcher.match(uri) == USER){ SQLiteDatabase db = mDbHelper.getReadableDatabase(); c = db.query(TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder); }else if (sUriMatcher.match(uri) == USER_NAME){ // format:authority/table/column/value-->0:table 1:column 2:value String name = uri.getPathSegments().get(2);// get name value Log.i("lily","query table:"+uri.getPathSegments().get(0)+" column:"+uri.getPathSegments().get(1)+" value:"+uri.getPathSegments().get(2)); SQLiteDatabase db = mDbHelper.getReadableDatabase(); if (selection != null){ if (selection.length()>0){ selection += "AND "+LilyUser.UserColumns.NAME+" like "+name; } } c = db.query(TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder); }else if (sUriMatcher.match(uri) == MULITABLE){ // format:authority/table1/table2 String table1 = uri.getPathSegments().get(0); String table2 = uri.getPathSegments().get(1); Log.i("lily","table1 = "+table1); Log.i("lily","table2 = "+table2); if (table1.equalsIgnoreCase(TABLE_NAME)){ if (table2.equals(PRODUCT_TABLE)){ SQLiteDatabase db = mDbHelper.getReadableDatabase(); if (selection != null){ if (selection.length()>0){ selection += "AND "+LilyUser.UserColumns._ID+" = "+LilyUser.ShopListColumns.USER_ID; } else{ selection = LilyUser.UserColumns._ID+" = "+LilyUser.ShopListColumns.USER_ID; } } else { selection = TABLE_NAME + "." +LilyUser.UserColumns._ID+" = "+PRODUCT_TABLE + "." + LilyUser.ShopListColumns.USER_ID; } c = db.query(table1+" cross join "+table2, projection, null, selectionArgs, null, null, sortOrder); } } } return c; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { Log.i("lily","LilyProvider-->update"); SQLiteDatabase db = mDbHelper.getWritableDatabase(); int rownum = db.update(TABLE_NAME, values, selection, selectionArgs); return rownum; } }
这个里面定义Uri格式的时候一定要小心,不然出错了死都查不出来。
下面是使用查询的方法:
private void queryNameUri() { Uri uri = Uri.withAppendedPath(LilyUser.User.CONTENT_URI, "name/lily");//content://com.ianc.lilyprovider/customer/name/lily String[] projection = {LilyUser.UserColumns._ID, LilyUser.UserColumns.NAME, LilyUser.UserColumns.PASSWORD}; String selection = null; String [] selectionArgs = null; String sortOrder = null; Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder); if (cursor == null){ Log.i("lily","cursor == null"); return; } if (cursor.moveToFirst()){ Log.i("lily","*********************************************"); String id; String name; String password; do{ id = cursor.getString(cursor.getColumnIndex(LilyUser.UserColumns._ID)); Log.i("lily","id = "+id); name = cursor.getString(cursor.getColumnIndex(LilyUser.UserColumns.NAME)); Log.i("lily","name = "+name); password = cursor.getString(cursor.getColumnIndex(LilyUser.UserColumns.PASSWORD)); Log.i("lily","password = "+password); Log.i("lily","*********************************************"); }while(cursor.moveToNext()); } else{ Log.i("lily","no result"); } cursor.close(); }
多表查询:
private void queryMultiTable() { String[] projection = {"customer."+LilyUser.UserColumns._ID, "customer."+LilyUser.UserColumns.NAME, "customer."+LilyUser.UserColumns.PASSWORD, "shoplist."+LilyUser.ShopListColumns.USER_ID, "shoplist."+LilyUser.ShopListColumns.PRODUCT, "shoplist."+LilyUser.ShopListColumns.DATE}; String selection = null; String [] selectionArgs = null; String sortOrder = null; Uri uri = Uri.withAppendedPath(LilyUser.User.CONTENT_URI, "shoplist"); Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder); if (cursor == null){ Log.i("lily","queryMultiTable()-->cursor == null"); return; } if (cursor.moveToFirst()){ Log.i("lily","*********************************************"); String id; String name; String password; String user_id; String product; String date; do{ id = cursor.getString(cursor.getColumnIndex(LilyUser.UserColumns._ID)); Log.i("lily","id = "+id); name = cursor.getString(cursor.getColumnIndex(LilyUser.UserColumns.NAME)); Log.i("lily","name = "+name); password = cursor.getString(cursor.getColumnIndex(LilyUser.UserColumns.PASSWORD)); Log.i("lily","password = "+password); user_id = cursor.getString(cursor.getColumnIndex(LilyUser.ShopListColumns.USER_ID)); Log.i("lily","user_id = "+user_id); product = cursor.getString(cursor.getColumnIndex(LilyUser.ShopListColumns.PRODUCT)); Log.i("lily","product = " + product); date = cursor.getString(cursor.getColumnIndex(LilyUser.ShopListColumns.DATE)); Log.i("lily","date = " + date); Log.i("lily","*********************************************"); }while(cursor.moveToNext()); } else{ Log.i("lily","no result"); } cursor.close(); }
接下来是LilyUser这个说明类的代码:
package com.ianc.lilyprovider; import android.net.Uri; import android.provider.BaseColumns; public class LilyUser { public static class User{ public static final Uri CONTENT_URI = Uri.parse("content://com.ianc.lilyprovider/" + "customer"); } public static class UserColumns implements BaseColumns{ public static String NAME = "name"; public static String PASSWORD = "password"; } public static class ShopList{ public static final Uri CONTENT_URI = Uri.parse("content://com.ianc.lilyprovider/" + "shoplist"); } public static class ShopListColumns implements BaseColumns{ public static String USER_ID = "user_id"; public static String PRODUCT = "product"; public static String DATE = "date"; } }