[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. 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. All these classes are provided at the URL in my git lab repository, shown at the bottom of this slide. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. Down here is the update implementation, we print some debugging information out. Then we see whether we're updating characters or a simple individual character then we make the appropriate method call. 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. Here we're doing the same sort of thing, just for an individual character. Once again we add the key ID check to the where statement. We'll look at that implementation shortly. 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. 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. 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]