1
00:00:04,200 --> 00:00:05,200
Welcome back.

2
00:00:05,560 --> 00:00:09,160
All right we've created the adapter for our reports.

3
00:00:09,560 --> 00:00:11,560
Now we need to check if it works.

4
00:00:12,360 --> 00:00:14,660
We'll be using a ViewModel eventually,

5
00:00:15,060 --> 00:00:19,060
but it's easier to test the adapter by creating an activity to use it.

6
00:00:19,560 --> 00:00:22,060
We need to create the activity anyway.

7
00:00:22,060 --> 00:00:24,360
And if we write our functions correctly,

8
00:00:24,360 --> 00:00:27,960
we can just move them into the ViewModel when we're ready to create it.

9
00:00:29,160 --> 00:00:31,660
We've already created the layouts for the activity,

10
00:00:31,660 --> 00:00:34,660
but we can still use the activity wizard for this class,

11
00:00:35,160 --> 00:00:37,660
we'll just delete the layouts that the wizard creates.

12
00:00:38,460 --> 00:00:39,960
Right click the package name,

13
00:00:42,360 --> 00:00:45,960
and choose new, activity, basic activity.

14
00:00:51,760 --> 00:00:54,120
Call the class DurationsReport.

15
00:00:58,480 --> 00:01:02,280
Remember to set the hierarchical parent to main activity.

16
00:01:07,980 --> 00:01:09,780
It's not the end of the world if you forget,

17
00:01:10,280 --> 00:01:13,480
you'll just have to edit the manifest and add the parent activity.

18
00:01:13,880 --> 00:01:15,380
Click finish to continue.

19
00:01:18,580 --> 00:01:22,580
You may get a dialogue like this one with some warnings about conflicts.

20
00:01:22,980 --> 00:01:26,180
I suspect this is a minor fault with the template code.

21
00:01:26,540 --> 00:01:28,900
Because if you check this class carefully,

22
00:01:29,260 --> 00:01:33,060
the one that's wanted is the same as the one that it already is.

23
00:01:33,720 --> 00:01:36,020
If you do get this, you can make a note of it

24
00:01:36,270 --> 00:01:38,170
and refer to it if you get problems.

25
00:01:38,720 --> 00:01:42,520
I think it popped up because there's no space before the closing

26
00:01:42,520 --> 00:01:45,820
backslash in the already is style.

27
00:01:46,620 --> 00:01:49,120
Xml doesn't require a space there,

28
00:01:49,480 --> 00:01:51,680
but it looks like the template codes

29
00:01:51,680 --> 00:01:55,280
just performed a basic search, which hasn't allowed for that.

30
00:01:55,640 --> 00:01:59,640
Anyway enough speculation. Let's proceed anyway.

31
00:02:02,940 --> 00:02:07,340
When android studio has finished creating the activity, close the layout.

32
00:02:11,000 --> 00:02:15,100
We're going to delete contentdurationsreport.xml soon

33
00:02:15,100 --> 00:02:18,600
because we've already created the layout that we'll use for the reports.

34
00:02:19,260 --> 00:02:21,860
All right. This is going to be a bit quick and dirty.

35
00:02:22,360 --> 00:02:24,560
The code we'll reuse will be fine,

36
00:02:24,810 --> 00:02:28,800
but the oncreate function probably isn't how you should write the code

37
00:02:28,800 --> 00:02:29,900
in a production app.

38
00:02:30,300 --> 00:02:33,400
I'll mention that when we get to it. When we do this properly,

39
00:02:33,400 --> 00:02:36,700
we'll want to allow the data to be sorted on the various columns.

40
00:02:37,250 --> 00:02:39,910
I'll create an enum for the column names

41
00:02:39,910 --> 00:02:42,110
to make it easier to see what we're doing.

42
00:02:42,510 --> 00:02:44,810
I'll also add the usual log tag.

43
00:02:59,510 --> 00:03:02,810
Next, we need to declare a variable for our adapter

44
00:03:03,210 --> 00:03:05,810
and also the cursor that will hold the data.

45
00:03:06,010 --> 00:03:09,310
I'll make the sort order default to the name column.

46
00:03:24,010 --> 00:03:27,510
We're also going to display records between a range of dates

47
00:03:28,310 --> 00:03:31,910
that will either be for an entire week or a single day.

48
00:03:32,410 --> 00:03:35,290
We'll do that by changing the selection arguments

49
00:03:35,290 --> 00:03:37,490
that we pass to the content resolver.

50
00:03:46,990 --> 00:03:49,190
I've hard coded the date range there.

51
00:03:49,850 --> 00:03:53,650
We'll be allowing the user to choose dates once everything's working properly,

52
00:03:53,650 --> 00:03:57,550
but for now I've just used the timestamps for the 1st

53
00:03:57,550 --> 00:03:59,150
to the 31st of May. In

54
00:03:59,850 --> 00:04:04,840
the oncreate function, we'll delete the floating action button code.

55
00:04:04,840 --> 00:04:09,830
I'll replace it with a call to setDisplayHomeAsUpEnabled

56
00:04:10,030 --> 00:04:11,330
and pass true.

57
00:04:18,990 --> 00:04:23,390
That adds the up bar to the toolbar to let us return to main activity.

58
00:04:23,940 --> 00:04:26,140
The code to initialize the adapter

59
00:04:26,140 --> 00:04:29,140
and associate it with the RecyclerView is standard.

60
00:04:29,500 --> 00:04:31,500
We've done the same thing a few times now.

61
00:04:41,500 --> 00:04:44,360
There's one more change to make to oncreate.

62
00:04:45,020 --> 00:04:47,620
We need to load the data into our cursor.

63
00:04:48,170 --> 00:04:52,470
I'm going to create a function to do that. I'll call it load data

64
00:04:52,970 --> 00:04:54,970
and add it below oncreate.

65
00:05:53,630 --> 00:05:56,510
This is very close to the final version of the function

66
00:05:56,510 --> 00:05:58,710
that we're going to use in our ViewModel class.

67
00:05:59,310 --> 00:06:03,310
It starts by setting order to the appropriate column that we want to order by

68
00:06:03,810 --> 00:06:05,410
using a when expression.

69
00:06:06,110 --> 00:06:09,370
We pass order to the content resolver's query function

70
00:06:09,370 --> 00:06:10,490
to sort the data.

71
00:06:11,590 --> 00:06:14,290
The call to query shouldn't need any explanation.

72
00:06:14,290 --> 00:06:15,790
We've done this a few times now.

73
00:06:16,450 --> 00:06:19,650
Remember that passing null for the projection

74
00:06:19,650 --> 00:06:22,010
will include every column in the data.

75
00:06:22,450 --> 00:06:25,450
That's usually what you want to do when you're using a database view.

76
00:06:25,950 --> 00:06:27,830
If you don't want any of the columns,

77
00:06:27,830 --> 00:06:30,430
you probably wouldn't have included them in the view.

78
00:06:31,090 --> 00:06:34,690
Of course, there are times when you want to use the same view

79
00:06:34,690 --> 00:06:35,890
for different purposes.

80
00:06:36,290 --> 00:06:38,990
In that case, you can provide a projection.

81
00:06:39,490 --> 00:06:41,790
But it's handy not having to bother setting one up.

82
00:06:42,090 --> 00:06:45,990
We wrote our SwapCursor function to return the old cursor

83
00:06:45,990 --> 00:06:48,490
when we provide a new one to the adapter.

84
00:06:49,090 --> 00:06:52,080
That allows us to call close on the old cursor

85
00:06:52,080 --> 00:06:53,680
to avoid leaking the resource.

86
00:06:54,480 --> 00:06:56,380
That's an acceptable thing to do.

87
00:06:57,180 --> 00:07:00,780
The cursor was created by the DurationsViewModel class,

88
00:07:01,280 --> 00:07:02,680
but that class doesn't use it.

89
00:07:03,340 --> 00:07:07,040
This DurationsReport class uses it for the adapter

90
00:07:07,040 --> 00:07:09,640
and knows when the old cursors can be closed.

91
00:07:10,540 --> 00:07:13,240
But what happens when we close the activity

92
00:07:13,600 --> 00:07:17,300
and return to main activity? Will our cursor get closed?

93
00:07:17,960 --> 00:07:19,860
The answer is no, it won't.

94
00:07:20,360 --> 00:07:24,660
It's our responsibility to free up any resources that we create.

95
00:07:25,160 --> 00:07:28,820
You may be tempted to close the cursor in the ondestroy function

96
00:07:29,320 --> 00:07:30,920
but that will cause problems.

97
00:07:31,920 --> 00:07:33,620
If you want to see what they are,

98
00:07:33,620 --> 00:07:36,620
add the ondestroy function at the end of the class.

99
00:07:57,620 --> 00:07:59,980
Calling swap cursor with null

100
00:07:59,980 --> 00:08:02,980
will return a reference to the existing cursor.

101
00:08:03,230 --> 00:08:06,480
If that's not null, we call its closed function

102
00:08:06,480 --> 00:08:07,780
to free up the resource.

103
00:08:08,780 --> 00:08:12,980
If you fully understand the various life cycles, you'll spot the problem here.

104
00:08:13,780 --> 00:08:16,780
Don't worry if you're not quite that comfortable with the life cycles yet,

105
00:08:17,280 --> 00:08:19,280
you'll spot the problem when the app crashes.

106
00:08:19,880 --> 00:08:21,080
If you want to try that,

107
00:08:21,080 --> 00:08:24,680
rotate the device while viewing the reports to cause the crash.

108
00:08:26,180 --> 00:08:30,170
Remember that the cursor is created by the DurationsViewModel

109
00:08:30,170 --> 00:08:32,870
and that will survive the configuration change,

110
00:08:33,370 --> 00:08:36,470
that means the database won't be re-queried

111
00:08:36,470 --> 00:08:39,169
and the adapter will try to read from this cursor,

112
00:08:39,720 --> 00:08:41,520
the one that we've just closed.

113
00:08:42,070 --> 00:08:46,060
I'll talk a bit more about this when we tidy the app up in the next section.

114
00:08:46,660 --> 00:08:49,260
For now, I'll just comment out this function.

115
00:08:53,660 --> 00:08:57,260
That will leave us with the resource leak, but we'll fix it later.

116
00:08:57,920 --> 00:09:01,220
Okay. Three more changes, and we're ready to test.

117
00:09:01,820 --> 00:09:05,420
The first is to call load data in our oncreate function.

118
00:09:11,620 --> 00:09:14,820
That's the bit I don't suggest you do in your final code.

119
00:09:15,480 --> 00:09:19,140
We're just testing our adapter here and our layouts too

120
00:09:19,140 --> 00:09:21,140
because we haven't seen them running yet.

121
00:09:21,910 --> 00:09:24,410
If you examine the logcat when we run the app,

122
00:09:24,410 --> 00:09:28,810
you'll see that the database is queried every time the device is rotated,

123
00:09:29,310 --> 00:09:33,860
that's fine for this test, and we're going to move load data into the ViewModel shortly.

124
00:09:34,560 --> 00:09:38,330
Okay. The next change is to use an intent

125
00:09:38,330 --> 00:09:41,330
to launch this activity when the menu item is tapped.

126
00:09:41,990 --> 00:09:44,090
We do that in main activity

127
00:09:44,090 --> 00:09:45,990
because that's where the main menu code is.

128
00:09:46,540 --> 00:09:50,340
We'll add another branch in OnOptionsItemsSelected.

129
00:10:10,000 --> 00:10:13,700
To tidy up, delete the unused content durations report

130
00:10:13,700 --> 00:10:15,700
xml layout file.

131
00:10:25,200 --> 00:10:29,000
That will cause an error in the activity durations report layout.

132
00:10:29,800 --> 00:10:33,200
You need to tell it to include task durations instead.

133
00:10:34,000 --> 00:10:36,500
Open up activities durations report,

134
00:10:39,500 --> 00:10:41,500
and select the include widget

135
00:10:42,380 --> 00:10:43,880
in the component tree.

136
00:10:44,280 --> 00:10:46,280
Using the symbol next to layout,

137
00:10:48,680 --> 00:10:50,680
select task durations.

138
00:10:54,680 --> 00:10:58,340
While we're here, delete the floating action button

139
00:10:58,340 --> 00:10:59,640
from the component tree.

140
00:11:03,300 --> 00:11:05,800
Okay. The app should now run.

141
00:11:10,200 --> 00:11:13,200
Tap the report icon the one that looks like an eye,

142
00:11:13,860 --> 00:11:16,860
that looks good and we've got a load of data for May.

143
00:11:17,410 --> 00:11:20,410
Scrolling the report should show different tasks.

144
00:11:23,910 --> 00:11:25,910
We can't sort the report at the moment,

145
00:11:26,460 --> 00:11:30,860
but the adapter looks to be working and our portrait layout lines up nicely.

146
00:11:31,660 --> 00:11:36,120
Rotate the emulator into landscape to check if landscape is also correct.

147
00:11:39,320 --> 00:11:41,020
If you get any problems,

148
00:11:41,020 --> 00:11:44,620
add logging to the adapter code to work out what's going wrong.

149
00:11:45,120 --> 00:11:47,000
If the data doesn't line up,

150
00:11:47,000 --> 00:11:50,000
check the margins and padding carefully in the layouts.

151
00:11:51,100 --> 00:11:53,300
The last test in this video

152
00:11:53,700 --> 00:11:55,700
is the up button on the toolbar.

153
00:11:56,500 --> 00:11:59,200
Tapping that should take us back to main activity.

154
00:12:01,800 --> 00:12:05,950
In the next video, we'll change the emulator to a different locale

155
00:12:05,950 --> 00:12:08,550
to make sure the dates are displayed correctly.

156
00:12:09,100 --> 00:12:10,100
I'll see you there.

