0:00
[MUSIC]
Welcome to the third part of our lesson,
which describes the HobbitContentProvider App Case Study.
After completing this part of the lesson,
you'll understand the implementation of the HobbitContentProvider App.
In particular, we focus on the content provider portions here.
0:22
We'll give a quick overview of these portions of the app.
There are several classes that are part of the content provider portion including
the HobbitProvider class, the HobbiDatabaseHelper class,
as well as several classes that handle meta data such as character record,
character contract, and character entry.
0:46
We're now back inside the Android CDO project file for
the HobbitContentProvider, we'll be looking at the contents of
the provider folder, starting with the CharacterContract.Java file.
Which defines the metadata used by the HobbitProvider including the provider's
access URIs, as well as its database constance.
We have a number of fields in this class, in fact this class is largely fields.
We have the CONTENT_AUTHORITY field, which is vandy.mooc.hobbitprovider,
which is going to be used to define the unique identifier.
It identifies the HobbitProvider,
we have the BASE_CONTENT-URI which uses the content authority,
to create the base of all URIs, which Apps will use to contact our HobbitProvider.
And we do this by essentially appending the content authority from here,
to the content:// prefix.
1:42
Then here we define our path character string, which is appended to
the BASE_CONTENT_URI for all the possible URIs, for example, a valid path for
looking at the character data that we'll use to store the Hobbit characters is
content://vandy.mooc.hobbitcontentprovide- r/character_table,
that's the SQL table that we use to actually store this.
The value of this string is set to character entry table name and
that comes down here in the character entry class which is a static final
nested class that defines the table contents of the Hobbit database table.
This implements the base columns interface and defines the number of fields.
It defines the CONTENT_URI field, and the CONTENT_URI field is basically used
by taking the BASE_CONTENT_URI field to find the bug.
And then the pending the PATH_CHARACTER that we justified up here,
to that CONTENT_URI.
We define a CONTENT_ITEMS_TYPE string, which is used when the cursor
returns a given URI by the ContentProvider that contains various items in it.
Here's the content item type, so
that's when we have one item versus zero or more items.
That is the plural on CONTENT_ITEMS versus the singular on CONTENT_ITEM.
And this basically defines something for
a dir versus an item and includes the other parts of the URI.
3:08
Down here, we have a string that contains the columns, the display,
which will be the ID of course, as well as the COLUMN_NAME and the COLUMN_RACE,
we're now defining the database table.
The name of the database table which would be stored in SQL light, is called
character underscore table, which we refer to by table underscore name.
We define symbolic constants for columns that are used to store data,
column name and column race, which are just name and race.
And finally, we have a helper method here, that's going to go ahead and
return a Uri that points to a row containing a given ID.
So we're going to go ahead and take the content URI that we defined up here right
there, and then we're going to go ahead and append the ID that's passed in here.
And you'll see how this gets used in a couple of places later.
Now that we've talked about that
part of the metadata let's talk about a character record.
A CharacterRecord is simply a plain old Java object,
or a POJO, that is used to store information about Hobbit characters.
We're going to go ahead and have the ID of the character,
we're going to have the name of the character and the race of the character.
Our constructor simply sets those fields and
increments the Id by one we're just doing auto increment by ourselves.
Down here we have another constructor that takes the id as a parameter and
sets that as one of the values.
4:30
Here is yet another constructor that initializes
the contents of the POJO from a cursor.
As you can see here, it goes ahead and looks up the column index for
the Id, stores that.
The column index for the name, stores that, the column index for
the race, and so on.
4:47
Down here we have a bunch of helper methods,
this is going to go ahead and take a cursor and return a new character record.
And then we have some other access or methods that get the ID,
get the name, get the race, and then also set the race.
So this is just a little helper class that we use to make it easier to manipulate
the various characters that we have in our database.
5:10
Speaking of databases, here is the HobbitDatabaseHelper which extends
the SQLiteOpenHelper, which is a class that's provided as part of
the Android implementation to make it easier to manage databases.
This will be used of course by the HobbitProvider, you can see here we have
the name of the database which we call vandy_.mooc_hobbit_db.
We keep track of which version we are dealing with here,
which is the first version, we only have one version of this right now.
Here's the SQL statement that's used to create the hobbit table, in the database.
You can see, we'd say, CREATE TABLE, that's an SQL command.
Given the table name that we're going to have the table included Id that
would be a primary key which is an integer.
And then we're going to have a column name and
a column race which are both text fields that are not null.
6:00
Down here we have the HobbitDatabaseHelper constructor, which goes ahead and
calls up to the superclass telling it we want to store this in the cache directory
using this database name and this field separator with this version.
So that will be used to decide where to actually store
the contents persistently on the database in the database file.
6:22
Here's the onCreate hook method which is used when the database is created.
And we go ahead and
execute that SQL instruction that's used to actually create the database.
And then finally,
we have another method here that will be called back, if the database is upgraded.
We don't do that in this implementation but we're going to go ahead and
drop the existing table name and then create a new database table.
6:47
Now, that we've describe all the various helper classes.
It's time to focus on the HobbitProvider class,
this is really where it all comes together.
This is the class that implements the content provider
the used to manage the covet characters which
are of course stored in the SQLiteDatabase we just discussed.
As you can see HobbitProvider extends content provider and
define several fields.
It has a debugging tag used by the logger,
it has an instance of the HobbitDatabaseHelper,
it has a context that we use to get access to the content provider, and so on.
It also defines several codes, one code is the plural code for
characters that's used when a URI is indicated, intended for
more than one item, or one or more items, that matches against given components.
And another code is called character, and
that's used when there's exactly one item matched against a given component.
7:41
Here is the URI matcher that does the work, that's initialized by the build
URI matcher factor method; we'll take a look at that in a second.
First let's take a look at the onCreate hook method, this simply goes ahead and
stores the contents of the content provider and then uses that context
to create the HobbitDatabaseHelper and stores that also in a field.
This method returns true and as you can see, everything works fine.
8:03
Here's to buildUriMatcher method, this is going to be used to match
each URI to one of the integer constants that were defined above.
You can see here we go ahead and create the URI matcher object, and then for
each type of URI that's added, we're going to create a corresponding code.
So, you can see here when we have the characters variant,
we're going to go ahead and create this URI.
When we have a character variant which indicates an individual item,
we're going to go ahead and create this URI.
This data structure, this magic data structure then used a little bit later on.
8:41
Here's the get type method,
you can see this is used to handle type request from client apps.
And it essentially returns the mime type of the data that's associated with
each URI.
As you can see down here we essentially match against our URI matcher and
if we've got characters we return content items type where that's plural whereas
if we get character, we go ahead and return content item type, the singular.
So that's a very canonical idiom you see
used throughout content providers in Android.
9:12
Let's now go take a look at the various methods that are implemented,
that are inherited form content provider, here's Insert.
As you see, insert takes a uri and a ContentValues object,
we go ahead and we match against our matcher.
In this case, we are only going to be able to insert characters, and so
we go ahead and we insert characters and
we'll take a look at that implementation in just a second.
We then get back a return value, which we're going to return as the result which
gives back the uri that was inserted.
And then we're going to go ahead and notify
any observers that a row was inserted, that's used by content observers.
Here's the insertCharacters method, as you can see here this method goes ahead and
gets a writable instance of the database so we can actually write to it.
So this is the SQLiteDatabase in right mode.
And then we go ahead and we insert in to the Hobbit character table,
the content values and then we go ahead and
take the result that comes back here, and we're going to use this to actually
build the URI that will be returned as the results of this method.
10:24
Here is the bulkInsert method, you can
see what bulkInsert does is it first goes ahead and does some logging operations so
you can tell what's going on when you look at this in logcat.
It then goes and figures out what the match is against the path in the the uri.
And, once again, we're supporting characters and we're going to go ahead and
bulk insert all the various characters that are included in this,
content values array.
And if we get anything inserted, we're going to notify any observers that
rows were inserted and we'll return a count of how many things were inserted.
11:01
Here is the actual bulInsertCharacters method,
this is the one that, once again, gets a writable database
begins a transaction because we're going to do multiple inserts.
And then we go ahead and we iterate through array of content values,
and we go ahead and we insert each of these things into the database
incrementing the count every time it succeeds.
When we're all done, we indicate that the current transaction was successful.
And then in the transaction and
return of the count of the number of things that were inserted.
11:31
Here's the implementation of the query operation, as you can see here,
we can query on a couple of different things.
We can query on a number of characters,
we can also query on a single character depending on what the UriMatcher returns.
We go ahead and
call queryCharacters or queryCharacter storing a cursor result, in either case.
And then we go ahead and register to to watch the content uri for
changes so that we can get notified later when things change.
Here's the queryCharacter, quaracters protocol,
we go ahead and add the selection.
We'll see add selection args is a helper method defined later that goes ahead or's
all the things together and then we go ahead and we query in the database.
On this table with the projection and
the selection and the selectionArgs, as well as the sortOrder.
So all those things are passed in to query for characters, and
then here's the same method that all the queries on a single character.
And we go ahead and we add the key Id, to the where statement,
which is another helper method, we'll take a look at shortly.
And this goes ahead and
makes the appropriate query mechanism that we're going to use for the query string.
12:57
If it turns out there's actually something to change then we go ahead and
notify the content resolver that is changed.
So they call the content observers then register it.
Here's update character, as you can see here, we add selector Args for
the various selections that we're doing.
And then we go ahead and we update that entry in the table, with the selection and
the selectionArgs, which we'll take a look at shortly.
13:35
Here's the delete method, delete is called to handle delete requests from the client
app, specifically, in our case, from the Hobbit apps helper class.
We print some debug information out, once again, do the match against the path and
the Uri to see whether or not we're doing characters or
a single character depending on what we get back,
we notify that we've gotten some changes that rows were deleted in the table.
Here's the deleteCharacters method implementation.
We add the selectorArgs using an OR and
use that as part of our selection to go ahead and delete
those entries from the database that's to delete all the characters that match.
Here we are deleting a single character, as you can see it's very similar except
this time we're deleting an individual character so we add the key id check
to the where statement to indicate we're deleting that one character.
Here is the add selectionArgs method,
this is a helper method that can concatenates all the selectionArgs for
a given selection using the given operation that we show here.
Do a little sanity checking to handle the case where we're passing null arguments.
And then we go ahead and we add the selectionArgs to the selectionResult.
And we're basically putting the operation In between each of these things which in
all the cases we've shown so far is the or operation.
So we're basically oring together all these selectionArgs.
For example, all the different types of races could be put in here.
And then we create the selectionResult and return that right after we print
out the results to the debugging logcat just to see what's going on.
15:11
Here is the add key to id check to where statement, a little bit of a mouthful.
This is a helper method that depends that given key id to
the end of the where statement parameter to indicate we just want
to handle an individual character not a group of characters.
As you can see what we do here is we add the and operation and we're going to
go ahead and add those things together along with the ID that we have here.
So we take the new statement and we add the character entry's ID here and
that will ensure that we only select an individual character.
15:49
Finally, there's just a couple of helper methods we use for debugging.
This is used to print the characters out to logcat, so we can see what's going on.
And here's another helper method where we go ahead and
print the selectionArgs out to logcat.
So that basically concludes our implementation.
As you can see, there's actually a fair amount of code involved here, although
a lot of it is kind of boilerplate code that you would typically copy and
paste and modify ever so
slightly from each content provider that you might happen to implement.
This concludes part three of our lesson that
presents a case study of the HobbitContentProvider App.
[MUSIC]