Download making-content-providers-U08928-JAN

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
MAKING CONTENT PROVIDERS
David Sutton/Ian Bayley
OUTLINE OF LECTURE
 Essential methods of a content provider
 Example provider
 Helper classes
 Implementation of the example
CONTENT PROVIDERS
 To make a content provider we must extend the abstract class
ContentProvider.
 We must override (at least) the following methods:
onCreate
Method called when the content provider
is created.
query
Performs a query over the content
provider
insert
Inserts a new row into the provider
delete
Deletes row(s) from the provider
update
Updates the values of particular column(s)
in particular row(s).
getType
Returns the MIME type of data at a
particular URI.
AN EXAMPLE CONTENT PROVIDER
 We will illustrate the creation of content providers by implementing a simple
provider that we can use to find the capital cities of various countries.
 The provider will expose a table that looks like this
Id
Country
Capital
1
France
Paris
2
Germany
Berlin
3
Italy
Rome
4
Spain
Madrid
URIS OF TABLES AND ROWS
 The capitals table itself will be identified by the URI
uk.ac.brookes.bayley.capitals/capitals
 Individual rows within the table are identified by adding a trailing row number
to the URI for the table. For instance the row for Germany would be identified
by
uk.ac.brookes.bayley.capitals/capitals/2
Id
Country
Capital
1
France
Paris
2
Germany
Berlin
3
Italy
Rome
4
Spain
Madrid
CLASSES THAT WILL HELP US
 We will store our data in an SQLite database.
 We will make use of the following classes to help us implement the
provider:
 SQLiteDatabase – Exposes methods to manage an SQLite
database
 SQLiteOpenHelper - Helper class to manage database creation
and version management
 SQLiteQueryBuilder – Utility class for building SQL queries.
 UriMatcher – Utility class that determines whether a given Uri
matches a given pattern.
 ContentValues – a set of key-value pairs where the key is a column
name and the value is a value to insert into that column
 We shall not be able to give complete descriptions of these classes,
but there definitions can be found in the android developer reference.
BASIC STRUCTURE OF THE
CONTENT PROVIDER
SQLiteOpenHelper
ContentProvider
CapitalsProvider
SQLLiteDatabase capitalsDb
UriMatcher uriMatcher
onCreate
query
insert
delete
update
getType
createWriteableDatabase
onCreate
onUpgrade
CapitalsDatabaseHelper
onCreate
onUpgrade
Called when the
database is created
performs an SQL
create statement
Called when the
database needs to
be upgraded. Our
implementation
simply drops the
table then calls
onCreate
CAPITALSPROVIDER
CONSTANTS AND NESTED CLASS
public class CapitalsProvider extends ContentProvider {
public static final String AUTHORITY = "uk.ac.brookes.bayley.capitals";
public static final Uri CONTENT_URI =
Uri.parse("content://" + AUTHORITY + "/capitals");
private SQLiteDatabase capitalsDB;
private static final String CAPITALS_TABLE = "capitals";
public static final String KEY_ID = "_id";
public static final String KEY_COUNTRY = "country";
public static final String KEY_CAPITAL = "capital";
...
private static class CapitalsDatabaseHelper extends SQLiteOpenHelper {
This is a static nested class
STATIC NESTED CLASSES
CapitalsProvider
static KEY_COUNTRY=“country”
static KEY_CAPITAL = “capital”
CapitalsDatabaseHelper
A static nested class is defined
within another class.
Objects of the nested class can
access static fields and methods of
the enclosing class
createWriteableDatabase()
onCreate()
onUpgrade()
public class CapitalsProvider extends ContentProvider {
...
private static class CapitalsDatabaseHelper extends SQLiteOpenHelper {
...
}
....
}
DATABASE HELPER
private static class CapitalsDatabaseHelper extends SQLiteOpenHelper {
public CapitalsDatabaseHelper(Context context, String name,
CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + CAPITALS_TABLE + " (" + KEY_ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ KEY_COUNTRY
+ " TEXT," + KEY_CAPITAL + " TEXT);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.execSQL("DROP TABLE IF EXISTS " + CAPITALS_TABLE);
onCreate(db);
}
}
CREATING THE DATABASE
db.execSQL("CREATE TABLE " + CAPITALS_TABLE + " (" + KEY_ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ KEY_COUNTRY
+ " TEXT," + KEY_CAPITAL + " TEXT);");
CREATE TABLE capitals(
id INTEGER PRIMARY KEY AUTOINCREMENT,
country TEXT
capital TEXT)
Id
Country
This column contains integer
values. The database will
automatically add increasing
values so that each row has a
unique value.
Capital
These two column contains text
values.
URI MATCHER
The code that creates our URIMatcher looks like this…
public static final String AUTHORITY = "uk.ac.brookes.bayley.capitals";
private static final int CAPITALS = 1;
private static final int COUNTRY_ID = 2;
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "capitals", CAPITALS);
uriMatcher.addURI(AUTHORITY, "capitals/#", COUNTRY_ID);
The calls to addURI add patterns that the can be matched, and integer codes
that will be returned if they do match. The # matches any number. We test for
matches using a method ‘match’.
So “uk.ac.brookes.bayley.capitals/capitals” matches the first pattern, and
CAPITALS is returned.
“uk.ac.brookes.bayley.capitals/capitals/3” matches the second pattern and
COUNTRY_ID is returned.
IMPLEMENTING CAPITALS PROVIDER:
ONCREATE
OnCreate should attempt to create the database, and return
true or false depending on whether it was successful in doing
this.
public boolean onCreate() {
CapitalsDatabaseHelper helper = new CapitalsDatabaseHelper(
this.getContext(), DATABASE_NAME, null,
DATABASE_VERSION);
this.capitalsDB = helper.getWritableDatabase();
return (capitalsDB != null);
}
IMPLEMENTING CAPITALS PROVIDER:
QUERY
The query method has the following signature
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sort) {
The parameters are as follows:
 uri – URI of the table or row to be queried
 projection, selection, selectioArgs – define a potential projection and/or
selection over the content provider. Can be null if we want to return all rows
and/or all columns.
 sort – defines the order in which rows are to be returned. Can be null if we do
not care what order we get the rows in.
The return value is a Cursor over the rows in the query.
IMPLEMENTING CAPITALS PROVIDER:
QUERY
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sort) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables(CAPITALS_TABLE);
if (uriMatcher.match(uri) == COUNTRY_ID) {
qb.appendWhere(KEY_ID + "=" + uri.getPathSegments().get(1));
}
Cursor c = qb.query(capitalsDB, projection, selection, selectionArgs,
null, null, sort);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
}
IMPLEMENTING CAPITALS PROVIDER:
INSERT
The insert method has the following signature
public Uri insert(Uri uri, ContentValues values)
Parameters:
uri- URI of the table into which we insert a value
values – a set of key value pairs. The keys are columns and the values are
values that those columns should have in an inserted row. For example we
might specify that the COUNTRY_COLUMN column should have the value
“Italy” and that the CAPITAL_COLUMN column should have the value
“Rome”
Returns:
A URI for the inserted row. For example if the row got inserted at index 2 we
would return uk.ac.brookes.bayley.capitals/capitals/2
IMPLEMENTING CAPITALS PROVIDER:
INSERT
public Uri insert(Uri uri, ContentValues values) {
long rowID = capitalsDB.insert(CAPITALS_TABLE, KEY_COUNTRY,
values);
if (rowID > 0) {
Uri newuri = ContentUris.withAppendedId(CONTENT_URI, rowID);
getContext().getContentResolver().notifyChange(newuri, null);
return uri;
} else
throw new SQLException("Failed to insert row into " + uri);
}
}
IMPLEMENTING CAPITALS PROVIDER:
UPDATE
The update method has the following signature:
public int update(Uri uri, ContentValues values, String where,
String[] whereArgs) {
Parameters:
 uri – the URI of the table or row to update
 values – a set of key-value pair expressing values to be inserted into
particular columns.
 where, whereArgs – express an SQL where clause defining the rows to be
updated
Returns:
The number of rows inserted.
IMPLEMENTING CAPITALS PROVIDER:
UPDATE
@Override
public int update(Uri uri, ContentValues values, String where,
String[] whereArgs) {
makeNewWhere is
a private method
defined on the next
slide
int matchResult = uriMatcher.match(uri);
String newWhere = makeNewWhere(where, uri, matchResult);
if (matchResult == COUNTRY_ID || matchResult == CAPITALS) {
int count = capitalsDB.update(CAPITALS_TABLE, values,
newWhere, whereArgs);
getContext().getContentResolver().notifyChange(uri, null);
return count;
} else
throw new IllegalArgumentException("Unknown URI " + uri);
}
IMPLEMENTING CAPITALS PROVIDER:
MAKENEWWHERE
private String makeNewWhere(String where, Uri uri, int matchResult) {
if (matchResult != COUNTRY_ID) {
return where;
} else {
String newWhereSoFar = KEY_ID + "=" +
uri.getPathSegments().get(1);
if (TextUtils.isEmpty(where))
return newWhereSoFar;
else
return newWhereSoFar + " AND (" + where + ')';
}
}
IMPLEMENTING CAPITALS PROVIDER:
DELETE
The delete method has the following signature:
public int delete(Uri uri, String where, String[] whereArgs)
Parameters:
 uri – the URI of the table or row from which we are deleting.
 where, whereArgs – represent an SQL where clause that defines which
rows should be deleted.
Returns:
The number of rows deleted.
IMPLEMENTING CAPITALS PROVIDER:
DELETE
public int delete(Uri uri, String where, String[] whereArgs) {
int matchResult = uriMatcher.match(uri);
String newWhere = makeNewWhere(where, uri, matchResult);
if (matchResult == COUNTRY_ID || matchResult == CAPITALS) {
int count = capitalsDB.delete(CAPITALS_TABLE, newWhere,
whereArgs);
getContext().getContentResolver().notifyChange(uri, null);
return count;
} else
throw new IllegalArgumentException("Unknown URI " + uri);
}
IMPLEMENTING CAPITALS PROVIDER:
GETTYPE
The getType method has the following signature
public String getType(Uri uri)
Parameter:
uri – URI of a table or row
Returns:
A String describing the MIME type of the data at the given URI. This should
start with “vnd.android.cursor.item” for a single record, or
“vnd.android.cursor.dir/” for multiple items.
IMPLEMENTING CAPITALS PROVIDER:
GETTYPE
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case CAPITALS:
return "vnd.android.cursor.dir/vnd.brookes.country";
case COUNTRY_ID:
return "vnd.android.cursor.item/vnd.brookes.country";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
SUMMARY
 We implement a content provider by extending the abstract class
ContentProvider and implementing its abstract methods:
 onCreate
 query
 insert
 delete
 update
 getType
 Various auxiliary classes: SQLiteDatabase, SQLiteOpenHelper,
SQLiteQueryBuilder, UriMatcher, ContentValues.