1
00:00:04,200 --> 00:00:05,200
Welcome back.

2
00:00:05,400 --> 00:00:09,200
We're going to let how users choose the date that the report will display,

3
00:00:09,560 --> 00:00:13,360
and we'll do that using the android DatePickerDialog class.

4
00:00:14,060 --> 00:00:17,060
That's going to show a dialog that will let the user pick a date.

5
00:00:17,560 --> 00:00:19,160
You'll probably guess that from the name.

6
00:00:20,060 --> 00:00:23,560
We've covered dialog quite extensively in earlier videos.

7
00:00:24,110 --> 00:00:27,610
There are a couple of oddities about the DatePickerDialogue.

8
00:00:27,910 --> 00:00:30,910
So although, I won't be explaining the code in detail,

9
00:00:31,410 --> 00:00:34,010
I will talk about a couple of things that aren't obvious.

10
00:00:35,510 --> 00:00:38,710
The first is, don't show a DatePickerDialogue.

11
00:00:39,370 --> 00:00:41,570
The recommended way to use one

12
00:00:41,570 --> 00:00:44,370
is to use a DialogFragment instead.

13
00:00:45,360 --> 00:00:47,860
Google recommend that in a guide at

14
00:00:47,860 --> 00:00:52,060
developer.android.com/guide/topics/ui

15
00:00:52,360 --> 00:00:55,360
/control/pickers.html.

16
00:00:56,560 --> 00:00:58,560
At the time I'm recording this,

17
00:00:58,560 --> 00:01:00,860
the guide is also a really good example

18
00:01:00,860 --> 00:01:03,960
of why you need to be thorough when reading documentation.

19
00:01:04,620 --> 00:01:06,420
Let's start at the top and see what I mean.

20
00:01:07,410 --> 00:01:11,010
The guide talks about the DatePicker and TimePicker dialog

21
00:01:11,010 --> 00:01:12,310
that android provides.

22
00:01:13,190 --> 00:01:14,990
The images are a bit out of date.

23
00:01:15,350 --> 00:01:18,650
We're going to get the snazzy new dialog when we run the app.

24
00:01:19,450 --> 00:01:20,950
Just below the images is

25
00:01:20,950 --> 00:01:24,610
Google's recommendation to use a DialogFragment

26
00:01:25,110 --> 00:01:26,910
to host the date or TimePicker.

27
00:01:27,570 --> 00:01:29,770
Our code will be easy to change.

28
00:01:29,770 --> 00:01:33,370
Just modify the show DatePickerDialog function

29
00:01:33,770 --> 00:01:35,770
so you can quickly experiment

30
00:01:35,770 --> 00:01:38,770
with using a DatePickerDialog directly if you want to.

31
00:01:40,270 --> 00:01:42,770
You'll get strange effects with the life cycle.

32
00:01:43,270 --> 00:01:46,470
The picker will be dismissed when you rotate the phone for example.

33
00:01:46,970 --> 00:01:50,970
That's what they mean when they say DialogFragment manages the

34
00:01:50,970 --> 00:01:52,570
dialog lifecycle for you.

35
00:01:53,270 --> 00:01:55,570
So we will use a DialogFragment.

36
00:01:56,170 --> 00:01:59,470
Now things get a bit interesting, and we have to be awake.

37
00:02:00,070 --> 00:02:04,170
The paragraph after that talks about using the support library.

38
00:02:04,570 --> 00:02:07,170
We've been recommending you do that all along.

39
00:02:08,039 --> 00:02:12,340
Google also, as a rule, recommend the support libraries.

40
00:02:13,590 --> 00:02:17,950
The note below that suggests that you use the platform version

41
00:02:17,950 --> 00:02:22,850
of DialogFragment, if your minimum SDK is 11 or higher.

42
00:02:23,250 --> 00:02:26,650
Whenever you come across notes like that in the documentation,

43
00:02:26,650 --> 00:02:27,850
ignore them.

44
00:02:28,250 --> 00:02:30,850
Yes, you can use the framework version

45
00:02:31,100 --> 00:02:35,400
but I suggest you don't. Use the support libraries whenever you can.

46
00:02:36,300 --> 00:02:40,700
As I said, this is a great example of why you need to read things carefully

47
00:02:41,060 --> 00:02:43,360
and follow the links in the documentation.

48
00:02:44,460 --> 00:02:47,460
The final link to DialogFragment in that note

49
00:02:47,660 --> 00:02:51,960
takes us to the reference for the platform version of DialogFragment.

50
00:02:52,510 --> 00:02:54,110
So let's have a quick look at it.

51
00:02:56,470 --> 00:02:59,270
Make sure you click the final link, not the one before.

52
00:02:59,270 --> 00:03:02,770
The first link goes to the support library DialogFragment.

53
00:03:03,370 --> 00:03:07,570
Okay. We're at the page containing the reference for DialogFragment.

54
00:03:08,070 --> 00:03:10,570
It was introduced in API 11,

55
00:03:10,570 --> 00:03:13,930
but notice the note just below the class hierarchy at the top.

56
00:03:14,730 --> 00:03:18,930
This class was deprecated in API level 28.

57
00:03:19,480 --> 00:03:23,480
So we've just seen a guide suggesting that we can use this class

58
00:03:23,480 --> 00:03:26,080
for android versions 11 and above

59
00:03:26,380 --> 00:03:29,040
and now we have reference documentation informing

60
00:03:29,040 --> 00:03:32,640
us that the class will be removed from android at some point in the future.

61
00:03:33,190 --> 00:03:35,690
API 28, android pie,

62
00:03:36,190 --> 00:03:38,390
was released in 2018.

63
00:03:39,090 --> 00:03:42,690
The class might not be available in android queue.

64
00:03:43,290 --> 00:03:44,890
It probably will be.

65
00:03:45,290 --> 00:03:48,590
Deprecated classes tend to stick around for a couple of versions.

66
00:03:49,140 --> 00:03:52,840
But if we go using it, at some point, our code is going to break.

67
00:03:53,340 --> 00:03:57,700
I won't do this. But if you check out the framework version of the fragment class,

68
00:03:58,060 --> 00:03:59,360
that's also deprecated.

69
00:03:59,960 --> 00:04:03,360
It won't be a surprise if the FrameworkActivity class

70
00:04:03,360 --> 00:04:05,360
is also deprecated at some point.

71
00:04:05,960 --> 00:04:08,960
You should be using the appcompat versions,

72
00:04:08,960 --> 00:04:13,160
support library versions rather than the framework versions.

73
00:04:14,150 --> 00:04:18,029
Okay. That was interesting, but it's not getting our code written for us,

74
00:04:18,029 --> 00:04:19,529
so back to android studio.

75
00:04:20,190 --> 00:04:22,690
You want a new Kotlin class

76
00:04:22,690 --> 00:04:24,990
that I'm going to call DatePickerFragment.

77
00:04:37,980 --> 00:04:40,980
Remember choose class from the kind.

78
00:04:43,580 --> 00:04:45,880
We need to subclass dialog fragment

79
00:04:46,430 --> 00:04:49,660
and be sure to choose the support library version to import

80
00:04:49,960 --> 00:04:50,960
if you get the choice.

81
00:04:51,610 --> 00:04:56,210
That's androidx.fragment.app.AppCompatDialogFragment,

82
00:04:56,810 --> 00:04:59,110
if you're using androidx as I am.

83
00:05:08,310 --> 00:05:11,610
We're also going to implement the DatePickerDialogues

84
00:05:11,610 --> 00:05:13,970
on DateSetListener interface,

85
00:05:14,470 --> 00:05:17,370
that's how we'll get the chosen date back to our activity.

86
00:05:27,370 --> 00:05:30,370
I'll add a log tag and some constants that we'll need

87
00:05:30,370 --> 00:05:32,670
when retrieving things like the dialog title.

88
00:05:46,370 --> 00:05:49,670
We're going to use this DatePicker for a couple of different purposes.

89
00:05:50,330 --> 00:05:53,130
We'll use it to allow the user to filter the data.

90
00:05:53,330 --> 00:05:56,530
We'll also use it to let them choose a date when deleting records.

91
00:05:57,520 --> 00:06:01,820
We saw how we can use a dialog ID to respond differently

92
00:06:01,820 --> 00:06:03,020
to different dialog.

93
00:06:03,680 --> 00:06:06,880
But the DatePickerDialog doesn't provide that facility.

94
00:06:07,480 --> 00:06:10,840
We don't get an ID passed back in the CallBack function.

95
00:06:11,340 --> 00:06:14,640
That's not a huge problem we can implement our own solution.

96
00:06:15,300 --> 00:06:18,000
To do that, we need to store the ID.

97
00:06:30,770 --> 00:06:33,970
We have to override the OnCreateDialog function

98
00:06:33,970 --> 00:06:35,470
to customize the DatePicker,

99
00:06:35,870 --> 00:06:37,470
then return an instance of it.

100
00:06:38,070 --> 00:06:41,670
This is all code that we've seen before. So I won't say too much about it.

101
00:06:42,370 --> 00:06:46,470
Remember to choose the java.util package for the date

102
00:06:46,470 --> 00:06:48,470
and Gregorian calendar objects.

103
00:06:49,270 --> 00:06:53,630
Android studio can generate the OnCreate dialog stub for us,

104
00:06:53,990 --> 00:06:57,990
then we'll set up the calendar and create our DatePickerDialogue.

105
00:08:24,670 --> 00:08:26,170
That's fairly straightforward.

106
00:08:26,670 --> 00:08:29,370
We're providing the ability to use a different title

107
00:08:29,670 --> 00:08:33,659
and can also initialize the DatePicker with a specific date,

108
00:08:33,659 --> 00:08:36,760
if needed. That's going to be useful

109
00:08:36,760 --> 00:08:41,260
because the user will probably expect their last chosen date to be remembered

110
00:08:41,659 --> 00:08:43,760
as they change the dates of their reports.

111
00:08:45,120 --> 00:08:48,420
Notice that given date is a nullable data type,

112
00:08:49,020 --> 00:08:51,790
there may not be a date provided in the arguments

113
00:08:51,790 --> 00:08:55,690
in which case get serializable will return null.

114
00:08:56,290 --> 00:08:59,950
We test for that before setting the calendar to given date.

115
00:09:00,720 --> 00:09:02,820
Recent versions of android studio

116
00:09:02,820 --> 00:09:06,020
havebecome a bit aggressive about flagging up possible

117
00:09:06,020 --> 00:09:07,620
null pointer exceptions.

118
00:09:08,320 --> 00:09:11,520
That's generally a good thing, but sometimes it's a bit annoying.

119
00:09:12,320 --> 00:09:15,980
You may get a warning about context possibly being null

120
00:09:16,340 --> 00:09:19,340
when passing it to the DatePickerDialogue constructor.

121
00:09:20,140 --> 00:09:22,140
Theoretically, it can be null

122
00:09:22,840 --> 00:09:24,640
but. What are we supposed to do if it is?

123
00:09:25,300 --> 00:09:27,600
The function has to return a dialog.

124
00:09:28,200 --> 00:09:31,600
The super function is annotated as at, not null.

125
00:09:32,100 --> 00:09:34,700
That means we can't return null ourselves.

126
00:09:35,300 --> 00:09:38,960
If get context returns null, we can't create the dialog.

127
00:09:39,460 --> 00:09:40,460
So what can we return?

128
00:09:41,450 --> 00:09:45,750
Now, if you want to be a bit paranoid, you could wrap the code,

129
00:09:46,000 --> 00:09:50,100
the code that creates the DatePickerDialog in a null check.

130
00:09:50,900 --> 00:09:55,260
You'd then have to throw an exception if get context does return null.

131
00:09:55,510 --> 00:09:58,810
If we pass null to the DatePickerDialogue constructor,

132
00:09:59,250 --> 00:10:01,350
we're going to get an exception anyway.

133
00:10:01,450 --> 00:10:03,450
So why bother raising our own.

134
00:10:04,350 --> 00:10:09,010
If the activity is null at this point, then there's nothing that can catch the exception.

135
00:10:09,510 --> 00:10:11,810
Our code is going to crash whatever we do.

136
00:10:12,360 --> 00:10:15,560
Remember that all this is just theoretical,

137
00:10:16,060 --> 00:10:16,960
in theory,

138
00:10:16,960 --> 00:10:20,460
GetContext or GetActivity if we'd use that instead,

139
00:10:20,760 --> 00:10:21,960
could return null.

140
00:10:22,620 --> 00:10:25,120
Our activity has just created the fragment.

141
00:10:25,720 --> 00:10:29,620
It would be a bizarre set of conditions that could result in the activity

142
00:10:29,620 --> 00:10:31,120
being null at this point,

143
00:10:31,720 --> 00:10:33,420
if it's even possible in practice.

144
00:10:34,620 --> 00:10:39,120
So if you've got a warning there, you can suppress the warning.

145
00:10:39,920 --> 00:10:42,280
Use the light bulb to choose the option,

146
00:10:47,080 --> 00:10:51,380
nullability mismatch based on java annotation options.

147
00:10:52,180 --> 00:10:54,180
Then choose the first one in the list

148
00:10:54,480 --> 00:10:56,840
to disable the warning for the entire class.

149
00:11:01,440 --> 00:11:05,800
Okay. Next, we need to implement the DatePickerCallback function.

150
00:11:06,780 --> 00:11:09,880
Android studio can generate that code for us as well

151
00:11:10,540 --> 00:11:13,140
after the OncReateDialog function.

152
00:11:55,500 --> 00:11:58,160
It's possible for the context to be null,

153
00:11:58,160 --> 00:12:01,040
which is why I've cast it to be a nullable

154
00:12:01,040 --> 00:12:02,640
OnDateSet listener

155
00:12:03,240 --> 00:12:06,840
and used a safe call when calling the OnDateSet function.

156
00:12:07,440 --> 00:12:10,100
The DatePickerDialog passes back the date

157
00:12:10,100 --> 00:12:14,100
as three separate values when it calls OnDateSet.

158
00:12:14,900 --> 00:12:17,400
It also passes in a reference to the view.

159
00:12:18,060 --> 00:12:21,860
We can take advantage of that and attach the ID to the view,

160
00:12:22,360 --> 00:12:26,260
that lets the caller check the ID in its OnDateSet

161
00:12:26,260 --> 00:12:29,260
and take a different action for different date pickers,

162
00:12:29,810 --> 00:12:32,810
we'll see that shortly. Unfortunately,

163
00:12:32,810 --> 00:12:34,810
we've also got an error on that line.

164
00:12:35,170 --> 00:12:38,830
Android studio is complaining because the view argument

165
00:12:38,830 --> 00:12:41,130
could be null. Once again,

166
00:12:41,380 --> 00:12:45,380
I'm going to delete the nullable type marker from the function signature.

167
00:12:48,980 --> 00:12:52,420
In case you're thinking that I'm just doing this with wild abandon

168
00:12:52,420 --> 00:12:56,080
and no thought of the consequences, I have checked the source code

169
00:12:56,080 --> 00:12:58,580
for the DatePickerDialogue class.

170
00:12:59,460 --> 00:13:02,260
You can check it yourself if you want to be really sure.

171
00:13:03,060 --> 00:13:07,660
Look for the OnClick method and notice that the year, month and day arguments

172
00:13:07,860 --> 00:13:11,460
that we get are all fields of that DatePicker object,

173
00:13:11,460 --> 00:13:12,760
the view parameter.

174
00:13:13,260 --> 00:13:17,860
If the view was null, the DatePickerDialog code would have already crashed

175
00:13:17,860 --> 00:13:20,360
when attempting to access those fields.

176
00:13:20,720 --> 00:13:25,080
We'll see that dialog ID value being retrieved from the views tag

177
00:13:25,080 --> 00:13:26,280
in the next video.

178
00:13:27,160 --> 00:13:29,760
Okay. The only other thing you may want to do

179
00:13:29,760 --> 00:13:33,890
is to make sure that the activity does implement the required interface.

180
00:13:34,490 --> 00:13:36,490
We've seen this a few times now.

181
00:13:36,850 --> 00:13:39,150
I'll do it in the OnAttach function,

182
00:13:39,150 --> 00:13:42,150
which I'll generate before OnDateSet.

183
00:13:51,150 --> 00:13:52,350
Be careful there.

184
00:13:53,010 --> 00:13:57,310
There's a deprecated OnAttach function that has an activity argument.

185
00:13:57,810 --> 00:14:00,170
We want the one that takes a context.

186
00:14:20,370 --> 00:14:22,930
That's our DatePicker fragment finished for now.

187
00:14:23,480 --> 00:14:25,380
We're going to have to make a change to it

188
00:14:25,380 --> 00:14:28,980
because there's a bug in earlier versions of the DatePickerDialog.

189
00:14:29,780 --> 00:14:32,080
The bug was fixed in lollipop, I think.

190
00:14:32,680 --> 00:14:35,180
But it's certainly present in Jelly Bean and KitKat,

191
00:14:35,180 --> 00:14:37,540
and we're targeting API 17.

192
00:14:38,420 --> 00:14:40,920
I'll come back to that once we've seen the bug.

193
00:14:41,820 --> 00:14:46,120
In the next video, we'll use this fragment in our durations report,

194
00:14:46,370 --> 00:14:47,670
and we'll do some testing.

195
00:14:48,270 --> 00:14:49,870
I'm looking forward to it. See you there.

196
00:14:51,770 --> 00:14:55,170
Actually just before we do go, I noticed a typo.

197
00:14:56,470 --> 00:15:00,830
Our DatePickerFragment, down here, has a lowercase D.

198
00:15:01,380 --> 00:15:03,980
It's a class. It should have an uppercase D.

199
00:15:04,740 --> 00:15:08,400
Select the name, get a refactor,

200
00:15:09,760 --> 00:15:12,760
rename and just change that

201
00:15:14,260 --> 00:15:15,260
to a capital D.

202
00:15:16,250 --> 00:15:19,250
That's much better. Now, I'll see you in the next video.

