Znalazłem najlepsze demo i wyjaśnienie dla ContentProvider i myślę, że jest zgodne ze standardami Androida.
Klasy kontraktowe
public static final String CONTENT_AUTHORITY = "com.androidessence.moviedatabase";
private static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
public static final String PATH_MOVIE = "movie";
public static final String PATH_GENRE = "genre";
i klasy wewnętrzne:
public static final class MovieEntry implements BaseColumns {
// Content URI represents the base location for the table
public static final Uri CONTENT_URI =
BASE_CONTENT_URI.buildUpon().appendPath(PATH_MOVIE).build();
// These are special type prefixes that specify if a URI returns a list or a specific item
public static final String CONTENT_TYPE =
"vnd.android.cursor.dir/" + CONTENT_URI + "/" + PATH_MOVIE;
public static final String CONTENT_ITEM_TYPE =
"vnd.android.cursor.item/" + CONTENT_URI + "/" + PATH_MOVIE;
// Define the table schema
public static final String TABLE_NAME = "movieTable";
public static final String COLUMN_NAME = "movieName";
public static final String COLUMN_RELEASE_DATE = "movieReleaseDate";
public static final String COLUMN_GENRE = "movieGenre";
// Define a function to build a URI to find a specific movie by it's identifier
public static Uri buildMovieUri(long id){
return ContentUris.withAppendedId(CONTENT_URI, id);
}
}
public static final class GenreEntry implements BaseColumns{
public static final Uri CONTENT_URI =
BASE_CONTENT_URI.buildUpon().appendPath(PATH_GENRE).build();
public static final String CONTENT_TYPE =
"vnd.android.cursor.dir/" + CONTENT_URI + "/" + PATH_GENRE;
public static final String CONTENT_ITEM_TYPE =
"vnd.android.cursor.item/" + CONTENT_URI + "/" + PATH_GENRE;
public static final String TABLE_NAME = "genreTable";
public static final String COLUMN_NAME = "genreName";
public static Uri buildGenreUri(long id){
return ContentUris.withAppendedId(CONTENT_URI, id);
}
}
Teraz tworzę bazę danych za pomocą SQLiteOpenHelper :
public class MovieDBHelper extends SQLiteOpenHelper{
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "movieList.db";
public MovieDBHelper(Context context){
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
addGenreTable(db);
addMovieTable(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
private void addGenreTable(SQLiteDatabase db){
db.execSQL(
"CREATE TABLE " + MovieContract.GenreEntry.TABLE_NAME + " (" +
MovieContract.GenreEntry._ID + " INTEGER PRIMARY KEY, " +
MovieContract.GenreEntry.COLUMN_NAME + " TEXT UNIQUE NOT NULL);"
);
}
private void addMovieTable(SQLiteDatabase db){
db.execSQL(
"CREATE TABLE " + MovieContract.MovieEntry.TABLE_NAME + " (" +
MovieContract.MovieEntry._ID + " INTEGER PRIMARY KEY, " +
MovieContract.MovieEntry.COLUMN_NAME + " TEXT NOT NULL, " +
MovieContract.MovieEntry.COLUMN_RELEASE_DATE + " TEXT NOT NULL, " +
MovieContract.MovieEntry.COLUMN_GENRE + " INTEGER NOT NULL, " +
"FOREIGN KEY (" + MovieContract.MovieEntry.COLUMN_GENRE + ") " +
"REFERENCES " + MovieContract.GenreEntry.TABLE_NAME + " (" + MovieContract.GenreEntry._ID + "));"
);
}
}
Dostawca treści:
public class MovieProvider extends ContentProvider {
// Use an int for each URI we will run, this represents the different queries
private static final int GENRE = 100;
private static final int GENRE_ID = 101;
private static final int MOVIE = 200;
private static final int MOVIE_ID = 201;
private static final UriMatcher sUriMatcher = buildUriMatcher();
private MovieDBHelper mOpenHelper;
@Override
public boolean onCreate() {
mOpenHelper = new MovieDBHelper(getContext());
return true;
}
public static UriMatcher buildUriMatcher(){
String content = MovieContract.CONTENT_AUTHORITY;
// All paths to the UriMatcher have a corresponding code to return
// when a match is found (the ints above).
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
matcher.addURI(content, MovieContract.PATH_GENRE, GENRE);
matcher.addURI(content, MovieContract.PATH_GENRE + "/
matcher.addURI(content, MovieContract.PATH_MOVIE, MOVIE);
matcher.addURI(content, MovieContract.PATH_MOVIE + "/
return matcher;
}
@Override
public String getType(Uri uri) {
switch(sUriMatcher.match(uri)){
case GENRE:
return MovieContract.GenreEntry.CONTENT_TYPE;
case GENRE_ID:
return MovieContract.GenreEntry.CONTENT_ITEM_TYPE;
case MOVIE:
return MovieContract.MovieEntry.CONTENT_TYPE;
case MOVIE_ID:
return MovieContract.MovieEntry.CONTENT_ITEM_TYPE;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Cursor retCursor;
switch(sUriMatcher.match(uri)){
case GENRE:
retCursor = db.query(
MovieContract.GenreEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder
);
break;
case GENRE_ID:
long _id = ContentUris.parseId(uri);
retCursor = db.query(
MovieContract.GenreEntry.TABLE_NAME,
projection,
MovieContract.GenreEntry._ID + " = ?",
new String[]{String.valueOf(_id)},
null,
null,
sortOrder
);
break;
case MOVIE:
retCursor = db.query(
MovieContract.MovieEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder
);
break;
case MOVIE_ID:
_id = ContentUris.parseId(uri);
retCursor = db.query(
MovieContract.MovieEntry.TABLE_NAME,
projection,
MovieContract.MovieEntry._ID + " = ?",
new String[]{String.valueOf(_id)},
null,
null,
sortOrder
);
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Set the notification URI for the cursor to the one passed into the function. This
// causes the cursor to register a content observer to watch for changes that happen to
// this URI and any of it's descendants. By descendants, we mean any URI that begins
// with this path.
retCursor.setNotificationUri(getContext().getContentResolver(), uri);
return retCursor;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long _id;
Uri returnUri;
switch(sUriMatcher.match(uri)){
case GENRE:
_id = db.insert(MovieContract.GenreEntry.TABLE_NAME, null, values);
if(_id > 0){
returnUri = MovieContract.GenreEntry.buildGenreUri(_id);
} else{
throw new UnsupportedOperationException("Unable to insert rows into: " + uri);
}
break;
case MOVIE:
_id = db.insert(MovieContract.MovieEntry.TABLE_NAME, null, values);
if(_id > 0){
returnUri = MovieContract.MovieEntry.buildMovieUri(_id);
} else{
throw new UnsupportedOperationException("Unable to insert rows into: " + uri);
}
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Use this on the URI passed into the function to notify any observers that the uri has
// changed.
getContext().getContentResolver().notifyChange(uri, null);
return returnUri;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int rows; // Number of rows effected
switch(sUriMatcher.match(uri)){
case GENRE:
rows = db.delete(MovieContract.GenreEntry.TABLE_NAME, selection, selectionArgs);
break;
case MOVIE:
rows = db.delete(MovieContract.MovieEntry.TABLE_NAME, selection, selectionArgs);
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
// Because null could delete all rows:
if(selection == null || rows != 0){
getContext().getContentResolver().notifyChange(uri, null);
}
return rows;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int rows;
switch(sUriMatcher.match(uri)){
case GENRE:
rows = db.update(MovieContract.GenreEntry.TABLE_NAME, values, selection, selectionArgs);
break;
case MOVIE:
rows = db.update(MovieContract.MovieEntry.TABLE_NAME, values, selection, selectionArgs);
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
if(rows != 0){
getContext().getContentResolver().notifyChange(uri, null);
}
return rows;
}
}
Mam nadzieję, że to ci pomoże.
Demo na GitHub: https://github.com/androidessence/MovieDatabase
Cały artykuł: https://guides.codepath.com/android/creating-content-providers
Bibliografia:
Uwaga: skopiowałem kod tylko dlatego, że link do dema lub artykułu może zostać w przyszłości usunięty.