使用一个ContentProvider操作多张表

使用一个ContentProvider操作多张表

在我们开发过程中,通常使用ContentProvider来操作数据。查询数据库中的一张表的数据我们创建一个ContentProvider提供操作,需要访问多张表中的数据时,可以创建多个对应的ContentProvider来操作数据。

当然,如果只用一个ContentProvider来操作同一个数据库中的多张表也是可以实现的。ContentProvider所提供的CRUD方法都是通过uri来实现,使用一个ContentProvider操作多张表,也就是说一个authority,然后多个CONTENT_URI对应多张表。思路大概就是这样子,下面给出代码,代码是在NotePad源码上做了修改:

NotePad类(契约类)中声明AUTHORITY,class Notes对应数据库中的Notes表,class NotesGroup对应 NotesGroup表,它们有各自的CONTENT_URI。

NotePad.java

public final class NotePad {
    public static final String AUTHORITY = "com.google.provider.NotePad";

    // This class cannot be instantiated
    private NotePad() {
    }

    /**
     * Notes table contract
     */
    public static final class Notes implements BaseColumns {

        // This class cannot be instantiated
        private Notes() {}

        /**
         * The table name offered by this provider
         */
        public static final String TABLE_NAME = "notes";

        /*
         * URI definitions
         */

        /**
         * The scheme part for this provider's URI
         */
        private static final String SCHEME = "content://";

        /**
         * Path parts for the URIs
         */

        /**
         * Path part for the Notes URI
         */
        private static final String PATH_NOTES = "/notes";

        /**
         * Path part for the Note ID URI
         */
        private static final String PATH_NOTE_ID = "/notes/";

        /**
         * 0-relative position of a note ID segment in the path part of a note ID URI
         */
        public static final int NOTE_ID_PATH_POSITION = 1;

        /**
         * Path part for the Live Folder URI
         */
        private static final String PATH_LIVE_FOLDER = "/live_folders/notes";

        /**
         * The content:// style URL for this table
         */
        public static final Uri CONTENT_URI =  Uri.parse(SCHEME + AUTHORITY + PATH_NOTES);

        /**
         * The content URI base for a single note. Callers must
         * append a numeric note id to this Uri to retrieve a note
         */
        public static final Uri CONTENT_ID_URI_BASE
            = Uri.parse(SCHEME + AUTHORITY + PATH_NOTE_ID);

        /**
         * The content URI match pattern for a single note, specified by its ID. Use this to match
         * incoming URIs or to construct an Intent.
         */
        public static final Uri CONTENT_ID_URI_PATTERN
            = Uri.parse(SCHEME + AUTHORITY + PATH_NOTE_ID + "/#");

        /**
         * The content Uri pattern for a notes listing for live folders
         */
        public static final Uri LIVE_FOLDER_URI
            = Uri.parse(SCHEME + AUTHORITY + PATH_LIVE_FOLDER);

        /*
         * MIME type definitions
         */

        /**
         * The MIME type of {@link #CONTENT_URI} providing a directory of notes.
         */
        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.google.note";

        /**
         * The MIME type of a {@link #CONTENT_URI} sub-directory of a single
         * note.
         */
        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.note";

        /**
         * The default sort order for this table
         */
        public static final String DEFAULT_SORT_ORDER = "modified DESC";

        /*
         * Column definitions
         */

        /**
         * Column name for the title of the note
         * 

Type: TEXT

*/
public static final String COLUMN_NAME_TITLE = "title"; /** * Column name of the note content *

Type: TEXT

*/
public static final String COLUMN_NAME_NOTE = "note"; /** * Column name for the creation timestamp *

Type: INTEGER (long from System.curentTimeMillis())

*/
public static final String COLUMN_NAME_CREATE_DATE = "created"; /** * Column name for the modification timestamp *

Type: INTEGER (long from System.curentTimeMillis())

*/
public static final String COLUMN_NAME_MODIFICATION_DATE = "modified"; public static final String COLUMN_NAME_GROUPID = "gid"; } public static final class NotesGroup implements BaseColumns { private NotesGroup(){} public static final String TABLE_NAME = "notesGroup"; private static final String SCHEME = "content://"; private static final String PATH_NOTES_GROUP = "/notesGroup"; private static final String PATH_NOTEGROUP_ID = "/notesGroup/"; /** * 0-relative position of a note ID segment in the path part of a note ID URI */ public static final int NOTE_ID_PATH_POSITION = 1; /** * The content:// style URL for this table */ public static final Uri CONTENT_URI = Uri.parse(SCHEME + AUTHORITY + PATH_NOTES_GROUP); public static final Uri CONTENT_ID_URI_BASE = Uri.parse(SCHEME + AUTHORITY + PATH_NOTEGROUP_ID); public static final Uri CONTENT_ID_URI_PATTERN = Uri.parse(SCHEME + AUTHORITY + PATH_NOTEGROUP_ID + "/#"); public static final String COLUMN_NAME_GROUPTITLE = "name"; }

1、在自定义ContentProvider类给sUriMatcher添加匹配项(两张表的匹配)

//Notes表
private static final int NOTES = 1;
private static final int NOTE_ID = 2;
//NotesGroup表
private static final int NotesGroup = 4;
private static final int NotesGroup_ID = 5;

sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);

sUriMatcher.addURI(NotePad.AUTHORITY, "notesGroup", NotesGroup);
sUriMatcher.addURI(NotePad.AUTHORITY, "notesGroup/#", NotesGroup_ID);

2、在CRUD操作代码(根据匹配项分别操作两张表)

  @Override
   public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
           String sortOrder) {
       // Constructs a new query builder and sets its table name
       SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
       String orderBy = null;

       switch (sUriMatcher.match(uri)) {
           // If the incoming URI is for notes, chooses the Notes projection
           case NOTES:
               qb.setTables(NotePad.Notes.TABLE_NAME);
               qb.setProjectionMap(sNotesProjectionMap);
               // If no sort order is specified, uses the default
               if (TextUtils.isEmpty(sortOrder)) {
                   orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;
               } else {
                   // otherwise, uses the incoming sort order
                   orderBy = sortOrder;
               }
               break;
           case NOTE_ID:
               qb.setTables(NotePad.Notes.TABLE_NAME);
               qb.setProjectionMap(sNotesProjectionMap);
               qb.appendWhere(
                   NotePad.Notes._ID +    // the name of the ID column
                   "=" +
                   uri.getPathSegments().get(NotePad.Notes.NOTE_ID_PATH_POSITION));
               if (TextUtils.isEmpty(sortOrder)) {
                   orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;
               } else {
                   // otherwise, uses the incoming sort order
                   orderBy = sortOrder;
               }
               break;
           //=====================================
           case NotesGroup:
               qb.setTables(NotePad.NotesGroup.TABLE_NAME);
               qb.setProjectionMap(sGroupProjectionMap);
               break;
           case NotesGroup_ID:
               qb.setTables(NotePad.NotesGroup.TABLE_NAME);
               qb.appendWhere(NotePad.NotesGroup._ID + "=" + uri.getPathSegments().get(NotePad.NotesGroup.NOTE_ID_PATH_POSITION));
               break;

           default:
               throw new IllegalArgumentException("Unknown URI " + uri);
       }

       SQLiteDatabase db = mOpenHelper.getReadableDatabase();

       Cursor c = qb.query(
           db,            // The database to query
           projection,    // The columns to return from the query
           selection,     // The columns for the where clause
           selectionArgs, // The values for the where clause
           null,          // don't group the rows
           null,          // don't filter by row groups
           orderBy        // The sort order
       );
       c.setNotificationUri(getContext().getContentResolver(), uri);
       return c;
   }

NotePadProvider类代码,代码中只给出query方法,其他操作方法按照同样思路写

NotePadProvider.java

public class NotePadProvider extends ContentProvider implements PipeDataWriter<Cursor> {
    private static final String TAG = "NotePadProvider";
    private static final String DATABASE_NAME = "note_pad.db";
    private static final int DATABASE_VERSION = 2;
    private static HashMap sNotesProjectionMap;
    private static HashMap sGroupProjectionMap;

    private static final String[] READ_NOTE_PROJECTION = new String[] {
            NotePad.Notes._ID,               // Projection position 0, the note's id
            NotePad.Notes.COLUMN_NAME_NOTE,  // Projection position 1, the note's content
            NotePad.Notes.COLUMN_NAME_TITLE, // Projection position 2, the note's title
    };
    private static final int READ_NOTE_NOTE_INDEX = 1;
    private static final int READ_NOTE_TITLE_INDEX = 2;

    private static final String[] READ_GROUP_PROJECTION = new String[]{
            NotePad.NotesGroup._ID,
            NotePad.NotesGroup.COLUMN_NAME_GROUPTITLE
    };

    private static final int READ_GROUP_GROUPTITLE_INDEX = 1;

    private static final int NOTES = 1;
    private static final int NOTE_ID = 2;

    private static final int NotesGroup = 4;
    private static final int NotesGroup_ID = 5;
    private static final UriMatcher sUriMatcher;

    // Handle to a new DatabaseHelper.
    private DatabaseHelper mOpenHelper;

    static {
        // Create a new instance
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

        // Add a pattern that routes URIs terminated with "notes" to a NOTES operation
        sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);

        // Add a pattern that routes URIs terminated with "notes" plus an integer
        // to a note ID operation
        sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);

        sUriMatcher.addURI(NotePad.AUTHORITY, "notesGroup", NotesGroup);
        sUriMatcher.addURI(NotePad.AUTHORITY, "notesGroup/#", NotesGroup_ID);

        sNotesProjectionMap = new HashMap();

        // Maps the string "_ID" to the column name "_ID"
        sNotesProjectionMap.put(NotePad.Notes._ID, NotePad.Notes._ID);

        // Maps "title" to "title"
        sNotesProjectionMap.put(NotePad.Notes.COLUMN_NAME_TITLE, NotePad.Notes.COLUMN_NAME_TITLE);

        // Maps "note" to "note"
        sNotesProjectionMap.put(NotePad.Notes.COLUMN_NAME_NOTE, NotePad.Notes.COLUMN_NAME_NOTE);

        // Maps "created" to "created"
        sNotesProjectionMap.put(NotePad.Notes.COLUMN_NAME_CREATE_DATE,
                NotePad.Notes.COLUMN_NAME_CREATE_DATE);

        // Maps "modified" to "modified"
        sNotesProjectionMap.put(
                NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE,
                NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE);

        sNotesProjectionMap.put(NotePad.Notes.COLUMN_NAME_GROUPID,NotePad.Notes.COLUMN_NAME_GROUPID);

        sGroupProjectionMap = new HashMap();
        sGroupProjectionMap.put(NotePad.NotesGroup._ID,NotePad.NotesGroup._ID);
        sGroupProjectionMap.put(NotePad.NotesGroup.COLUMN_NAME_GROUPTITLE,NotePad.NotesGroup.COLUMN_NAME_GROUPTITLE);
    }

    /**
    *
    * This class helps open, create, and upgrade the database file. Set to package visibility
    * for testing purposes.
    */
   static class DatabaseHelper extends SQLiteOpenHelper {

       DatabaseHelper(Context context) {

           // calls the super constructor, requesting the default cursor factory.
           super(context, DATABASE_NAME, null, DATABASE_VERSION);
       }

       @Override
       public void onCreate(SQLiteDatabase db) {
           db.execSQL("CREATE TABLE " + NotePad.Notes.TABLE_NAME + " ("
                   + NotePad.Notes._ID + " INTEGER PRIMARY KEY,"
                   + NotePad.Notes.COLUMN_NAME_TITLE + " TEXT,"
                   + NotePad.Notes.COLUMN_NAME_NOTE + " TEXT,"
                   + NotePad.Notes.COLUMN_NAME_CREATE_DATE + " INTEGER,"
                   + NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE + " INTEGER,"
                   + NotePad.Notes.COLUMN_NAME_GROUPID + " INTEGER"
                   + ");");

           db.execSQL("CREATE TABLE " + NotePad.NotesGroup.TABLE_NAME +" ("
                   + NotePad.NotesGroup._ID + " INTEGER PRIMARY KEY,"
                   + NotePad.NotesGroup.COLUMN_NAME_GROUPTITLE + " TEXT"
                   + ");"
           );
       }

       @Override
       public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

           // Logs that the database is being upgraded
           Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
                   + newVersion + ", which will destroy all old data");

           // Kills the table and existing data
           db.execSQL("DROP TABLE IF EXISTS notes");
           db.execSQL("DROP TABLE IF EXISTS notesGroup");

           // Recreates the database with a new version
           onCreate(db);
       }
   }


   @Override
   public boolean onCreate() {

       // Creates a new helper object. Note that the database itself isn't opened until
       // something tries to access it, and it's only created if it doesn't already exist.
       mOpenHelper = new DatabaseHelper(getContext());

       // Assumes that any failures will be reported by a thrown exception.
       return true;
   }

   @Override
   public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
           String sortOrder) {
       // Constructs a new query builder and sets its table name
       SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
       String orderBy = null;

       switch (sUriMatcher.match(uri)) {
           // If the incoming URI is for notes, chooses the Notes projection
           case NOTES:
               qb.setTables(NotePad.Notes.TABLE_NAME);
               qb.setProjectionMap(sNotesProjectionMap);
               // If no sort order is specified, uses the default
               if (TextUtils.isEmpty(sortOrder)) {
                   orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;
               } else {
                   // otherwise, uses the incoming sort order
                   orderBy = sortOrder;
               }
               break;

           /* If the incoming URI is for a single note identified by its ID, chooses the
            * note ID projection, and appends "_ID = " to the where clause, so that
            * it selects that single note
            */
           case NOTE_ID:
               qb.setTables(NotePad.Notes.TABLE_NAME);
               qb.setProjectionMap(sNotesProjectionMap);
               qb.appendWhere(
                   NotePad.Notes._ID +    // the name of the ID column
                   "=" +
                   // the position of the note ID itself in the incoming URI
                   uri.getPathSegments().get(NotePad.Notes.NOTE_ID_PATH_POSITION));
               // If no sort order is specified, uses the default
               if (TextUtils.isEmpty(sortOrder)) {
                   orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;
               } else {
                   // otherwise, uses the incoming sort order
                   orderBy = sortOrder;
               }
               break;
           //=====================================
           case NotesGroup:
               qb.setTables(NotePad.NotesGroup.TABLE_NAME);
               qb.setProjectionMap(sGroupProjectionMap);
               break;
           case NotesGroup_ID:
               qb.setTables(NotePad.NotesGroup.TABLE_NAME);
               qb.appendWhere(NotePad.NotesGroup._ID + "=" + uri.getPathSegments().get(NotePad.NotesGroup.NOTE_ID_PATH_POSITION));
               break;

           //=======================================
           case LIVE_FOLDER_NOTES:
               // If the incoming URI is from a live folder, chooses the live folder projection.
               qb.setProjectionMap(sLiveFolderProjectionMap);
               break;

           default:
               // If the URI doesn't match any of the known patterns, throw an exception.
               throw new IllegalArgumentException("Unknown URI " + uri);
       }


       // Opens the database object in "read" mode, since no writes need to be done.
       SQLiteDatabase db = mOpenHelper.getReadableDatabase();

       /*
        * Performs the query. If no problems occur trying to read the database, then a Cursor
        * object is returned; otherwise, the cursor variable contains null. If no records were
        * selected, then the Cursor object is empty, and Cursor.getCount() returns 0.
        */
       Cursor c = qb.query(
           db,            // The database to query
           projection,    // The columns to return from the query
           selection,     // The columns for the where clause
           selectionArgs, // The values for the where clause
           null,          // don't group the rows
           null,          // don't filter by row groups
           orderBy        // The sort order
       );

       // Tells the Cursor what URI to watch, so it knows when its source data changes
       c.setNotificationUri(getContext().getContentResolver(), uri);
       return c;
   }

    DatabaseHelper getOpenHelperForTest() {
        return mOpenHelper;
    }
}

通过这种方法就可以实现使用一个ContentProvider来操作多张表,什么时候使用一个ContentProvider什么时候使用多个呢?像我呢,开发时不想多写一个ContentProvider就想到这个方法,其实看个人习惯吧。但如果数据库表中表数量变化,最好还是分开写好一点。

你可能感兴趣的:(android,android)