Welcome back.
We've got the layouts for our reports.
Next we need to create an adapter to provide the data for the RecyclerView.
Most of this will be very similar to our existing
cursor RecyclerView adapter
that we created back in section 10.
This one won't be responding to taps, so it's a bit simpler.
It does have to perform some date formatting, but other than that,
it's a basic adapter.
If you're not sure how an adapter works with a RecyclerView,
it's worth watching those earlier videos again.
Okay. Right click the package name and create
new Kotlin File/Class
and call it DurationsRVAdapter.
The name of the other adapter is a bit long
because it wanted to warn you about the problems you could get with logging tags.
I'll keep this one short by using RV rather than RecyclerView.
It's useful to have that in the name
because there are different types of adapters.
Change the kind to class to save a bit of typing.
Then click okay.
Our class will extend RecyclerView.adapter,
and we'll need to provide a view holder.
We've already used the layout container interface
to avoid having to call find view by ID.
Our adapter will need to be a sub class
of RecyclerView.adapter class,
and we'll need to provide it with the context and the cursor.
This is the same as we did for the cursor RecyclerView adapter class.
I'll generate the functions we need to override
just after the class declaration.
The code for the GetItemCount function is straightforward.
We're not doing anything fancy here. There are no records to display.
The RecyclerView will just be blank.
We also need the SwapCursor function,
and I can copy that from our cursory RecyclerView.adapter class.
It appears near the end of that class.
I'll paste it just after the functions that we've generated.
The code for this function is identical to the other adapter.
In fact, you'll probably use the same code or something very similar
in all your RecyclerView.adapters that use a cursor.
The oncreateviewholder function is also very simple.
It just inflates a view from our layout
and uses it to create a ViewHolder then returns the ViewHolder.
We're going to do some basic date formatting,
so the app can display dates in a format that our users will expect.
Dates in the United States appear with the month first,
while in Europe and Australia amongst other places,
the day appears before the month.
There are also differences in the date separator that's used.
Some countries use a slash, others use a dot.
We can use a date format object for that
to handle the formatting of the dates for us.
When you're prompted for the import,
make sure you choose the one from android text format.
I'm going to add another function to this adapter.
We're going to be using durations, which we want to format in hours,
minutes and seconds.
Using a colon to separate the three parts should be universally understood
but we can't use a standard date formatter to do that.
The reason is that the current duration for a task
could be more than 24 hours.
We're displaying the total duration for a week.
And in a week, our users could easily spend
more than 24 hours on a task. The
normal date, time formatting functions
will either attempt to convert that to days, hours, minutes and seconds
or give an incorrect result when attempting to represent it as a time of day.
If we try to use normal date formatting,
it's going to go horribly wrong.
Date classes can't handle a time with more than 24 hours.
I'll add the function after onbindviewholder
and call it formatDuration.
There's not a lot to say about that.
It takes number of seconds, calculates the hours,
minutes and seconds remaining and returns them as a formatted string.
We use a default locale,
the one that the user has specified in the device settings.
Some languages, such as Thai for example,
use different characters for the digits,
and the user may have specified that these are the ones that they want.
All right. The last function we need to write is onbindviewholder.
Once again, it's fairly standard code except for a bit of date formatting.
I'll paste the code rather than typing it.
You can pause the video here with the code on the screen,
so that you can catch up with the code.
There's nothing clever in there.
We use a local variable for the cursor
to allow Kotlin to perform smart casts after a null check.
Most of the code just retrieves the data from the cursor.
Note that we can refer to the ViewHolder fields directly
because it implements the layout container interface,
allowing the widgets to be accessed via the synthetic import
instead of find view by ID.
I'll discuss that date format briefly.
If you're dealing with dates and times,
you want to format them in a way that the user expects.
Up on line 25, we created an instance of the date format class.
The getDateFormat function is past a context,
and it can use that to work out which locale it should use
when formatting dates.
We'll test that later
and make sure that the dates do appear as they should
in different parts of the world.
Use ctrl Q or ctrl J on a mac
to call up the documentation for that getDateFormat function.
If you press control Q or control J a second time,
your documentation will be locked to the right hand edge of the window,
which can be more convenient.
GetDateFormat returns an object
that can format a date according to the current locale
that means we'll get a different format on an American phone
then I'll get on my Australian one.
All the emulators are set to the United States locale by default.
But we'll change that later to make sure everything's working.
The other thing to check is that we don't try to access the description
if the device is in portrait.
We didn't include a texture for the description in the portrait layout.
Rather than test for null,
I've used the Kotlin safe call operator,
that's tidier than the equivalent java.
But I like to include a comment, a question mark is quite easy to miss
when you're reading the code. That's our adapter finished.
We've had to do a bit of processing on the data but all the hard work,
totaling the daily durations for each task
was performed when we created the view that we're using.
In the next video, we'll create an activity to display the data
so we can view our reports.
The code will be temporary
because we'll be using a view model to provide the data to the adapter.
That will prevent things like having to re-query the database
if the device is rotated.
If we wait until I've written the view model before testing our adapter code,
it can be harder to work out where any problems are.
Also note that I haven't included any logging
in this durations RV adapter code.
You know how to do that now. And if you get any problems,
adding logging will be your first step to diagnosing them.
All right. I'll see you in the next video.