Alright so the update method's almost
the same as the query method. We have to
allow all URIs because you can
update a single record or all records in
the table. And we don't return a cursor.
Instead we use the databases update
method just as we use the insert method
in our insert function. The other
difference to insert, is that an update
statement can have a WHERE clause, and we
saw that in the SQL videos earlier in
this course. When I didn't specify a
WHERE clause I ended up giving everyone
the same email address. So the parameters
to our update method are a combination of
the insert and query parameters. We'll be
looking at the ContentValues and
selectionArgs parameters when we come
to use them, so don't worry about them
too much just yet. We'll just pass them
on to the database update method. So I'm
going to start off by taking a copy of
those three lines that we've used in the
other two functions; the two log lines and
the match variable which is returning
the value of uriMatcher.match.
I'm going to paste that into our update
method, and you can see again, that the
parameters to this update method are a
combination of the insert and query
parameters. Alright, so once again as
you can see, we're going to be using our
uriMatcher. And the other thing we want to do is
just type in a couple of other lines
here. We've got val count: int and
var selectionCriteria: string. Now
when we successfully update rows, the
database will let us know how many rows
were updated, and we'll also have to deal
with the selection criteria, so that's
what these two variables that I've
defined are actually for. So I'm going
to add the when statement and start with
the code for the Tasks table, so let's go
ahead and do that. So when, and I'll just
move this up, and you can see a bit more of the
screen at once.
So when parentheses match and left and
right curly braces, and then I'm
going to type TASKS arrow
and open a code block, and the code for
that's going to be val db equals AppDatabase
dot getInstance. Then in parentheses it's
going to be context, dot writable
Database, because obviously we're writing
to the database. And then we're going
to do count equals db.update parentheses
TasksContract.TABLE_
NAME comma values comma selection comma
and then finally selectionArgs. So there's not
really a lot to say about that. We get a
writableDatabase object and we call its
update method to perform the update. We
have to specify the table name as well
as the values to update, and we also
specify the selection criteria that will
be used in the SQL WHERE clause. Then
we just pass on the values that were
provided when our update function was
called to the update method. And then the
databases update method will return a
count of the number of rows that were
updated, so we'll use that as the return
value for this method. At the moment you
can see that I've saved that into the
variable count. Now for some reason this
return value is an int rather than a
long, which is strange. The ID values are
defined as long, so it's possible to
perform an update that affects more rows
and can be stored in an int variable.
Unless there's more than two billion
records I don't suppose it's something
we need to worry about on an Android
device. We'd run out of storage space
most likely well before the int value
could overflow, but you should get into
the habit of noticing anomalies
like this. Alright so that's the
code for performing an update against
the whole table. If, on the other hand, a
single row only needs to be updated, we
have to then include the row selection
in the WHERE clause. So let's start
writing some code for that scenario. So
that's going to be, on the next line,
TASKS_ID with our arrow and a
code block, and we'll start by val db
equals AppDatabase.getInstance
parentheses context dot writable
Database again.
And we'll do a val id equals Tasks
Contract.getId uri; selection
Criteria, we're going to set that equal to double
quotes $ left and right curly
braces TasksContract.Columns dot
ID. Then close off the right curly brace,
equals $id, and then we're going to put
a test in here. We're going to put if
selection is not equal to null and
selection.isNotEmpty, and then
we're going to put selectionCriteria
plus equals double quotes space AND
space, and then in parentheses
$selection. Enclose the parentheses
as well and double quote. And outside of
that if test, we're going to type count
equals db.update parentheses, and
it's going to be TasksContract dot, our TABLE
_NAME comma values comma selection
Criteria comma then selectionArgs, selectionArgs.
Alright so what are we
doing here? Well we start by getting the
ID from the URI using the getId
function that we wrote in the Tasks
Contract class. We then have to build up a
string containing the condition for the
WHERE clause. So that looks simple. It's
just underscore ID equals and the ID, and you
can see that on line 185. But if we look
at the parameters to this method, the
caller could also have passed in an
additional selection. They may, for
example, want to update a row only if
there's a certain value in one of the
other columns. So our code has to include
that condition as well. So therefore we
check to see if the selection parameter
contains something, then we add it to the
selection criteria if and only if it
does. So the selection criteria may end
up with something like tasks dot
underscore ID equals 8, and name equals
single quotes Tim, for example. Now our
database app won't need to use selection
criteria like that,
but you should allow conditions like
that to be used when writing your
content providers. Okay, so the code for
the Timings table is practically
identical to this, other than the fact
we'll be using the TimingsContract
class instead of the TasksContract. So
I'm going to copy that code and make
some changes based on the different
table names. So it's going to be TASKS,
instead of TASKS it's going to be
TIMINGS, and for the TASKS_ID that's
going to be TIMINGS_ID, and for Tasks
Contract here that's going to be Timings
Contract.
TIMINGS_ID down here is
going to be TimingsContract. Down here,
also the count equals db.
update, that will also be Timings
Contract. Alright so that should be
that. So to finish this function now, we
just need to add the exception if
there's an invalid URL, and then
return the count of rows updated. So
let's go ahead and do that. So below this
TIMINGS_ID, we have one other scenario
there and that's else with the arrow again,
it's going to be throw Illegal
ArgumentException, parentheses there
double quotes Unknown uri colon
$uri double quotes and right
parenthesis. And then to close off the
function, Log.d parentheses TAG comma
double quotes there, Exiting update,
returning $count, then double quote
right parenthesis. Then we'll return
count. Alright, so that's our update
function now written. Now the delete
function's almost identical to the
update function. We just call the
databases delete method, and it also
doesn't have a ContentValues parameter
to worry about. And you can see down the
bottom of the screen there, the method,
the function signature there. So I'm
going to copy the code from the update
method, basically everything, not
including the function declaration
self, just everything between the
opening and closing braces, like so. I'll just
copy that,
I'm going to paste that in, over-writing
the TODO, and basically in the function
like so. Alright so we just need to make
a few changes, and I should change this as well.
I'm going to take the opportunity to change
this because I didn't previously - update.
I'm actually going to put update in there
because that was copied from query
initially. So we want to know where we're
actually calling the update method - that
would mean more than likely the insert
one I've got wrong as well, update that
to insert, query insert. And we'll just go
up and check - query's obviously the one
where it copied from so that's correct -
but that should be all we need to do
there. And we'll go down to our delete
function. I'm also going to make sure that
says delete as well,
delete called, delete down there as well.
Alright so we need to make a few changes
here. So firstly for the Tasks table, it's
not going to be db.update. In
fact, what it's going to be is db dot
delete, so I'm going to type delete there, and there's also
another values argument there so I'm
going to delete that out. So we've just got our
TasksContract.TABLE_NAME, selection then
selectionArgs. Then moving down to our
TASKS_ID, the thing we need to
change there is change the db dot
update to a delete. Then we want to delete the
values and the comma, and the two things,
two parameters we want to leave in
after the TABLE_NAME are selection
Criteria and selectionArgs. And then we
want to do the same for TIMINGS and
TIMINGS_ID, and you can notice
there that that's something I've
actually missed there - TimingsContract. I
need to fix that - it should be Tasks
Contract so lucky I checked that - and we
need to change this also, up here, so I'm
going to make that a delete. I'm going to
delete the values in the semi, in the
comma as well to make that valid. Also
down here I'm going to delete, convert it to
delete, a call to the delete method
instead of update, and also remove values
comma from that line. And that should be
that, but then the only other thing I
need to do because I've found this problem
in TIMINGS_ID and we copied
that from the update method, that would
mean that the code needs
to be fixed here for TIMINGS_ID.
So I'm going to change that to, from
TimingsContract, paste in Timings
Contract there instead of TasksContract.
Now as it turns out that would have
worked anyway because the TasksContract dot
Columns.ID and TimingsContract dot
Columns.ID were set to the same
value, but obviously for some reason if we
renamed it in the future this code
would break. So it's best to get it right
at the time we're actually writing
the code if we can see that there's a
fault there. Alright so let's bring our
delete back on the screen again, our delete
function, and what we've done now should
be everything we need to do. We're just going to
have a quick look now to make sure that
we've got everything as it should be, and I
think that looks pretty good to me.
And obviously we'll find out if there's
a problem when we go to test this
anyway. So you can see that the delete
function's pretty well doing much the
same as the update function, and instead
of updating rows its deleting them. So at
this point that's our ContentProvider
pretty well finished. You will see later
though, that there's one more thing we
need to do in all three functions that
change the data; the insert, update and
delete functions. But it's a simple
change and I'll discuss that when we
come to it. For now though, I'm going to
stop the video here and then we're going
to test these functions in the next one.
So I'll see you in the next video.