Welcome back.
We're going to let how users choose the date that the report will display,
and we'll do that using the android DatePickerDialog class.
That's going to show a dialog that will let the user pick a date.
You'll probably guess that from the name.
We've covered dialog quite extensively in earlier videos.
There are a couple of oddities about the DatePickerDialogue.
So although, I won't be explaining the code in detail,
I will talk about a couple of things that aren't obvious.
The first is, don't show a DatePickerDialogue.
The recommended way to use one
is to use a DialogFragment instead.
Google recommend that in a guide at
developer.android.com/guide/topics/ui
/control/pickers.html.
At the time I'm recording this,
the guide is also a really good example
of why you need to be thorough when reading documentation.
Let's start at the top and see what I mean.
The guide talks about the DatePicker and TimePicker dialog
that android provides.
The images are a bit out of date.
We're going to get the snazzy new dialog when we run the app.
Just below the images is
Google's recommendation to use a DialogFragment
to host the date or TimePicker.
Our code will be easy to change.
Just modify the show DatePickerDialog function
so you can quickly experiment
with using a DatePickerDialog directly if you want to.
You'll get strange effects with the life cycle.
The picker will be dismissed when you rotate the phone for example.
That's what they mean when they say DialogFragment manages the
dialog lifecycle for you.
So we will use a DialogFragment.
Now things get a bit interesting, and we have to be awake.
The paragraph after that talks about using the support library.
We've been recommending you do that all along.
Google also, as a rule, recommend the support libraries.
The note below that suggests that you use the platform version
of DialogFragment, if your minimum SDK is 11 or higher.
Whenever you come across notes like that in the documentation,
ignore them.
Yes, you can use the framework version
but I suggest you don't. Use the support libraries whenever you can.
As I said, this is a great example of why you need to read things carefully
and follow the links in the documentation.
The final link to DialogFragment in that note
takes us to the reference for the platform version of DialogFragment.
So let's have a quick look at it.
Make sure you click the final link, not the one before.
The first link goes to the support library DialogFragment.
Okay. We're at the page containing the reference for DialogFragment.
It was introduced in API 11,
but notice the note just below the class hierarchy at the top.
This class was deprecated in API level 28.
So we've just seen a guide suggesting that we can use this class
for android versions 11 and above
and now we have reference documentation informing
us that the class will be removed from android at some point in the future.
API 28, android pie,
was released in 2018.
The class might not be available in android queue.
It probably will be.
Deprecated classes tend to stick around for a couple of versions.
But if we go using it, at some point, our code is going to break.
I won't do this. But if you check out the framework version of the fragment class,
that's also deprecated.
It won't be a surprise if the FrameworkActivity class
is also deprecated at some point.
You should be using the appcompat versions,
support library versions rather than the framework versions.
Okay. That was interesting, but it's not getting our code written for us,
so back to android studio.
You want a new Kotlin class
that I'm going to call DatePickerFragment.
Remember choose class from the kind.
We need to subclass dialog fragment
and be sure to choose the support library version to import
if you get the choice.
That's androidx.fragment.app.AppCompatDialogFragment,
if you're using androidx as I am.
We're also going to implement the DatePickerDialogues
on DateSetListener interface,
that's how we'll get the chosen date back to our activity.
I'll add a log tag and some constants that we'll need
when retrieving things like the dialog title.
We're going to use this DatePicker for a couple of different purposes.
We'll use it to allow the user to filter the data.
We'll also use it to let them choose a date when deleting records.
We saw how we can use a dialog ID to respond differently
to different dialog.
But the DatePickerDialog doesn't provide that facility.
We don't get an ID passed back in the CallBack function.
That's not a huge problem we can implement our own solution.
To do that, we need to store the ID.
We have to override the OnCreateDialog function
to customize the DatePicker,
then return an instance of it.
This is all code that we've seen before. So I won't say too much about it.
Remember to choose the java.util package for the date
and Gregorian calendar objects.
Android studio can generate the OnCreate dialog stub for us,
then we'll set up the calendar and create our DatePickerDialogue.
That's fairly straightforward.
We're providing the ability to use a different title
and can also initialize the DatePicker with a specific date,
if needed. That's going to be useful
because the user will probably expect their last chosen date to be remembered
as they change the dates of their reports.
Notice that given date is a nullable data type,
there may not be a date provided in the arguments
in which case get serializable will return null.
We test for that before setting the calendar to given date.
Recent versions of android studio
havebecome a bit aggressive about flagging up possible
null pointer exceptions.
That's generally a good thing, but sometimes it's a bit annoying.
You may get a warning about context possibly being null
when passing it to the DatePickerDialogue constructor.
Theoretically, it can be null
but. What are we supposed to do if it is?
The function has to return a dialog.
The super function is annotated as at, not null.
That means we can't return null ourselves.
If get context returns null, we can't create the dialog.
So what can we return?
Now, if you want to be a bit paranoid, you could wrap the code,
the code that creates the DatePickerDialog in a null check.
You'd then have to throw an exception if get context does return null.
If we pass null to the DatePickerDialogue constructor,
we're going to get an exception anyway.
So why bother raising our own.
If the activity is null at this point, then there's nothing that can catch the exception.
Our code is going to crash whatever we do.
Remember that all this is just theoretical,
in theory,
GetContext or GetActivity if we'd use that instead,
could return null.
Our activity has just created the fragment.
It would be a bizarre set of conditions that could result in the activity
being null at this point,
if it's even possible in practice.
So if you've got a warning there, you can suppress the warning.
Use the light bulb to choose the option,
nullability mismatch based on java annotation options.
Then choose the first one in the list
to disable the warning for the entire class.
Okay. Next, we need to implement the DatePickerCallback function.
Android studio can generate that code for us as well
after the OncReateDialog function.
It's possible for the context to be null,
which is why I've cast it to be a nullable
OnDateSet listener
and used a safe call when calling the OnDateSet function.
The DatePickerDialog passes back the date
as three separate values when it calls OnDateSet.
It also passes in a reference to the view.
We can take advantage of that and attach the ID to the view,
that lets the caller check the ID in its OnDateSet
and take a different action for different date pickers,
we'll see that shortly. Unfortunately,
we've also got an error on that line.
Android studio is complaining because the view argument
could be null. Once again,
I'm going to delete the nullable type marker from the function signature.
In case you're thinking that I'm just doing this with wild abandon
and no thought of the consequences, I have checked the source code
for the DatePickerDialogue class.
You can check it yourself if you want to be really sure.
Look for the OnClick method and notice that the year, month and day arguments
that we get are all fields of that DatePicker object,
the view parameter.
If the view was null, the DatePickerDialog code would have already crashed
when attempting to access those fields.
We'll see that dialog ID value being retrieved from the views tag
in the next video.
Okay. The only other thing you may want to do
is to make sure that the activity does implement the required interface.
We've seen this a few times now.
I'll do it in the OnAttach function,
which I'll generate before OnDateSet.
Be careful there.
There's a deprecated OnAttach function that has an activity argument.
We want the one that takes a context.
That's our DatePicker fragment finished for now.
We're going to have to make a change to it
because there's a bug in earlier versions of the DatePickerDialog.
The bug was fixed in lollipop, I think.
But it's certainly present in Jelly Bean and KitKat,
and we're targeting API 17.
I'll come back to that once we've seen the bug.
In the next video, we'll use this fragment in our durations report,
and we'll do some testing.
I'm looking forward to it. See you there.
Actually just before we do go, I noticed a typo.
Our DatePickerFragment, down here, has a lowercase D.
It's a class. It should have an uppercase D.
Select the name, get a refactor,
rename and just change that
to a capital D.
That's much better. Now, I'll see you in the next video.