1
00:00:00,019 --> 00:00:02,422
(gentle, futuristic music)

2
00:00:02,422 --> 00:00:05,620
(keyboard typing)

3
00:00:05,620 --> 00:00:06,453
Right, so we've got

4
00:00:06,453 --> 00:00:08,490
the user interface working well now,

5
00:00:08,490 --> 00:00:11,510
so it's time to get our app to save the data.

6
00:00:11,510 --> 00:00:13,940
In the life cycle videos, I mentioned that you may

7
00:00:13,940 --> 00:00:15,930
prefer to save the data automatically

8
00:00:15,930 --> 00:00:18,420
in the onPause or onStop functions.

9
00:00:18,420 --> 00:00:20,920
That's the decision you make when designing your apps,

10
00:00:20,920 --> 00:00:23,390
and will probably be a good decision for this one.

11
00:00:23,390 --> 00:00:25,940
We're going to use the save button instead.

12
00:00:25,940 --> 00:00:28,900
We're doing that so we can take a look at using dialogues,

13
00:00:28,900 --> 00:00:30,190
which wouldn't be appropriate in

14
00:00:30,190 --> 00:00:32,900
the onPause or onStop functions.

15
00:00:32,900 --> 00:00:34,250
Both of those functions should

16
00:00:34,250 --> 00:00:35,980
finish as quickly as possible,

17
00:00:35,980 --> 00:00:38,040
and popping up a dialogue isn't a good idea

18
00:00:38,040 --> 00:00:40,570
from these life cycle functions.

19
00:00:40,570 --> 00:00:42,380
Interrupting the life cycle while your app

20
00:00:42,380 --> 00:00:45,090
waits for a user to dismiss the dialogue isn't a good thing

21
00:00:45,090 --> 00:00:47,970
to do, in fact, it's a very bad thing to do.

22
00:00:47,970 --> 00:00:49,970
When you've seen the code to save the task data,

23
00:00:49,970 --> 00:00:53,200
then by all means move it into onPause or onStop,

24
00:00:53,200 --> 00:00:56,200
for now we'll put it in the save button's onClickListener,

25
00:00:56,200 --> 00:00:58,790
so that we can cover using dialogues in this app.

26
00:00:58,790 --> 00:01:01,690
Before we can save the details, we need to populate

27
00:01:01,690 --> 00:01:05,010
our edit text widgets with the task details.

28
00:01:05,010 --> 00:01:08,400
Remember that this fragment's being used to add a new task,

29
00:01:08,400 --> 00:01:11,510
as well as edit existing task details.

30
00:01:11,510 --> 00:01:13,770
If the argument passed to the fragment is null,

31
00:01:13,770 --> 00:01:16,860
then we're adding a new task, otherwise the argument

32
00:01:16,860 --> 00:01:19,380
will be the task that we're editing.

33
00:01:19,380 --> 00:01:20,981
I've already mentioned that we can't change

34
00:01:20,981 --> 00:01:23,480
UI elements in the onCreate function,

35
00:01:23,480 --> 00:01:25,860
because our UI doesn't exist at that point.

36
00:01:25,860 --> 00:01:28,123
It's not inflated until onCreateView.

37
00:01:29,100 --> 00:01:31,280
A good place to modify the UI is

38
00:01:31,280 --> 00:01:33,710
in the onViewCreated function.

39
00:01:33,710 --> 00:01:36,760
When that gets called, we know our layout's been inflated,

40
00:01:36,760 --> 00:01:38,660
and all the views exist.

41
00:01:38,660 --> 00:01:41,039
We're already overriding onViewCreate in our

42
00:01:41,039 --> 00:01:43,839
AddEditFragment, and I'll just bring that on the screen.

43
00:01:46,750 --> 00:01:48,200
And we're overriding onViewCreated

44
00:01:48,200 --> 00:01:50,490
so that we could just see it being called.

45
00:01:50,490 --> 00:01:52,230
I could leave it where it is,

46
00:01:52,230 --> 00:01:55,233
and it's right down towards the bottom of the file here.

47
00:01:56,570 --> 00:01:59,500
There it is, onViewCreated, but I prefer to have the life

48
00:01:59,500 --> 00:02:02,720
cycle functions appearing in the order they get called.

49
00:02:02,720 --> 00:02:05,040
All the life cycle functions that we've added

50
00:02:05,040 --> 00:02:07,000
were just there so we could log them,

51
00:02:07,000 --> 00:02:08,460
and we'll leave them still at the

52
00:02:08,460 --> 00:02:10,410
end of the AddEditFragment file,

53
00:02:10,410 --> 00:02:13,770
but I'll move the ones we really want up as we use them.

54
00:02:13,770 --> 00:02:15,080
So for this one, we're going

55
00:02:15,080 --> 00:02:17,340
to cut the onViewCreated function

56
00:02:18,980 --> 00:02:22,640
where it is, and what I'm going to do is paste it

57
00:02:22,640 --> 00:02:26,973
just after the onCreateView function, just here.

58
00:02:30,770 --> 00:02:31,603
Okay.

59
00:02:32,873 --> 00:02:35,060
Right, so in terms of what we want to do here,

60
00:02:35,060 --> 00:02:39,090
if a task exists, we'll set its values into the widgets,

61
00:02:39,090 --> 00:02:41,940
we'll also log what we're doing to make debugging easier.

62
00:02:43,700 --> 00:02:46,570
Right, so in terms of code, we don't need the call to

63
00:02:46,570 --> 00:02:48,920
the super function, so I'm going to delete that line,

64
00:02:48,920 --> 00:02:50,280
but how do I know that?

65
00:02:50,280 --> 00:02:52,453
Well if we CMD or CTRL click that,

66
00:02:55,052 --> 00:02:55,885
and we're checking out the source code,

67
00:02:55,885 --> 00:02:58,620
and as you can see, the function body's empty,

68
00:02:58,620 --> 00:03:00,020
so we know that the super function

69
00:03:00,020 --> 00:03:02,010
is not actually doing anything.

70
00:03:02,010 --> 00:03:05,400
OnViewCreated is called after onCreateView,

71
00:03:05,400 --> 00:03:06,670
but, and this is the interesting bit,

72
00:03:06,670 --> 00:03:09,400
it's called before any save state

73
00:03:09,400 --> 00:03:11,450
has been restored to the view.

74
00:03:11,450 --> 00:03:13,090
That's important, because we're about

75
00:03:13,090 --> 00:03:15,750
to populate the edit text widgets with the

76
00:03:15,750 --> 00:03:18,550
data from the task to be edited.

77
00:03:18,550 --> 00:03:20,820
If the user rotates the device,

78
00:03:20,820 --> 00:03:23,210
these life cycle methods get called again,

79
00:03:23,210 --> 00:03:26,220
and we'll be resetting the widgets to the values they had

80
00:03:26,220 --> 00:03:28,650
when the fragment was first created.

81
00:03:28,650 --> 00:03:31,040
But if we do that after state is restored,

82
00:03:31,040 --> 00:03:33,810
we'd be replacing any edits that the users made.

83
00:03:33,810 --> 00:03:36,050
That wouldn't be good, if all their changes

84
00:03:36,050 --> 00:03:38,980
got wiped out because they rotated their phone.

85
00:03:38,980 --> 00:03:40,710
Because state hasn't been restored yet,

86
00:03:40,710 --> 00:03:42,823
the values we're about to put into the widgets

87
00:03:42,823 --> 00:03:46,460
will be replaced with any text that the users have typed.

88
00:03:46,460 --> 00:03:48,760
So we'll go back to AddEditFragment,

89
00:03:48,760 --> 00:03:51,293
close down this fragment source code.

90
00:03:52,220 --> 00:03:54,260
So we'll actually delete that line and then add the code

91
00:03:54,260 --> 00:03:56,463
and we'll come back to that point shortly.

92
00:03:58,210 --> 00:04:03,200
I can start by typing if task, and task is in parentheses,

93
00:04:03,200 --> 00:04:07,350
is not equal to null, I put a code block,

94
00:04:07,350 --> 00:04:09,800
and then we're going to do a Log.d parentheses

95
00:04:09,800 --> 00:04:11,800
TAG comma, double quotes, onViewCreated,

96
00:04:14,070 --> 00:04:16,882
colon space, Task details found,

97
00:04:18,089 --> 00:04:20,413
comma, editing task, $,

98
00:04:21,610 --> 00:04:25,523
left and right curly braces and we'll go with task.id.

99
00:04:27,870 --> 00:04:28,860
And we're going to ignore the

100
00:04:28,860 --> 00:04:30,500
error that you see there for task,

101
00:04:30,500 --> 00:04:32,550
and we'll get a few of those errors as we type this in,

102
00:04:32,550 --> 00:04:35,240
and I'll explain that a little bit later in the video.

103
00:04:35,240 --> 00:04:37,723
Alright, next line, addedit_name.setText,

104
00:04:40,070 --> 00:04:42,420
we're setting the text for the widget,

105
00:04:42,420 --> 00:04:45,183
and it's going to be task.name.

106
00:04:46,880 --> 00:04:51,083
Addedit_description.setText,

107
00:04:52,980 --> 00:04:54,160
parentheses for that, will be

108
00:04:54,160 --> 00:04:57,700
task.description in parentheses.

109
00:04:57,700 --> 00:04:58,533
Then the third line,

110
00:04:58,533 --> 00:05:03,533
addedit_sortorder.setText again,

111
00:05:03,900 --> 00:05:06,800
parentheses, and within the parentheses, Integer.toString,

112
00:05:11,550 --> 00:05:14,907
and in parentheses, it'll be task.sortOrder.

113
00:05:18,362 --> 00:05:20,250
Alright, so that's the code, if task isn't null,

114
00:05:20,250 --> 00:05:23,370
else, the code block for else will be,

115
00:05:23,370 --> 00:05:25,210
we'll just put a comment here so we know what we're doing.

116
00:05:25,210 --> 00:05:27,993
So basically no task, so we must be adding a new task,

117
00:05:34,420 --> 00:05:36,020
and not editing an existing one.

118
00:05:38,760 --> 00:05:40,020
So we'll just add a log at this stage,

119
00:05:40,020 --> 00:05:42,850
Log.d, parentheses TAG comma,

120
00:05:42,850 --> 00:05:44,103
double quotes, onViewCreated,

121
00:05:45,880 --> 00:05:48,693
colon No arguments,

122
00:05:49,720 --> 00:05:50,620
adding new record.

123
00:05:52,810 --> 00:05:55,650
Alright, so that's pretty straightforward and simple code.

124
00:05:55,650 --> 00:05:59,300
We're just displaying the task details if there is a task.

125
00:05:59,300 --> 00:06:01,780
It's a bit of a waste of time doing that if the details

126
00:06:01,780 --> 00:06:04,400
are only going to be replaced by the user's edits.

127
00:06:04,400 --> 00:06:07,390
Fortunately, we know about the fragment life cycle

128
00:06:07,390 --> 00:06:10,070
and we know that the savedInstanceState argument

129
00:06:10,070 --> 00:06:12,160
for this method will be null when

130
00:06:12,160 --> 00:06:13,850
the fragment's first created.

131
00:06:13,850 --> 00:06:16,760
Then after that, after our rotation for example,

132
00:06:16,760 --> 00:06:18,730
the savedInstanceState bundle will contain

133
00:06:18,730 --> 00:06:21,500
the data from the edit text widgets.

134
00:06:21,500 --> 00:06:23,450
We can check that and then only populate

135
00:06:23,450 --> 00:06:25,890
the widgets ourselves if that's necessary.

136
00:06:25,890 --> 00:06:27,580
So let's add the code to do that.

137
00:06:27,580 --> 00:06:29,393
We want to surround our other code,

138
00:06:30,470 --> 00:06:32,360
so if parentheses, and it's going to be

139
00:06:32,360 --> 00:06:34,903
savedInstanceState is not equal to null,

140
00:06:36,780 --> 00:06:39,880
closing parentheses, at the left curly brace,

141
00:06:39,880 --> 00:06:42,530
I'm going to add the right curly brace down here

142
00:06:42,530 --> 00:06:45,210
right just before the end of the function,

143
00:06:45,210 --> 00:06:46,820
we should indent everything nicely.

144
00:06:46,820 --> 00:06:48,570
Alright, so I've now wrapped that in that test

145
00:06:48,570 --> 00:06:51,713
to see whether savedInstanceState is not equal to null.

146
00:06:51,713 --> 00:06:52,760
And in fact, that should have been

147
00:06:52,760 --> 00:06:54,993
if savedInstanceState is equal to null,

148
00:06:56,729 --> 00:06:58,300
because again, what we're trying to do,

149
00:06:58,300 --> 00:07:02,280
we know that savedInstanceState argument will be null

150
00:07:02,280 --> 00:07:03,970
when the fragment's first created.

151
00:07:03,970 --> 00:07:05,850
So what we're doing a test for here

152
00:07:05,850 --> 00:07:09,070
is if it is null, in other words if it's first created,

153
00:07:09,070 --> 00:07:10,670
then we're grabbing the data

154
00:07:10,670 --> 00:07:13,250
and populating the various widgets.

155
00:07:13,250 --> 00:07:15,090
And this also saves processing, which is

156
00:07:15,090 --> 00:07:17,270
kinder on our user's batteries.

157
00:07:17,270 --> 00:07:18,930
Alright, so we've got those errors that I mentioned

158
00:07:18,930 --> 00:07:21,610
when I referred to task in the code.

159
00:07:21,610 --> 00:07:24,300
This is a more extreme example of the problem

160
00:07:24,300 --> 00:07:26,230
I referred to in a previous video,

161
00:07:26,230 --> 00:07:29,570
when we tried to cast the listener to AppCompatActivity,

162
00:07:29,570 --> 00:07:32,323
and the error is if I go over any of these references.

163
00:07:33,320 --> 00:07:35,880
Smart cast to Task is impossible because Task

164
00:07:35,880 --> 00:07:37,450
is a mutable property that could

165
00:07:37,450 --> 00:07:39,860
have been changed by this time.

166
00:07:39,860 --> 00:07:41,280
Now we've just tested for null

167
00:07:41,280 --> 00:07:43,520
and we know that Task won't change.

168
00:07:43,520 --> 00:07:46,010
The Kotlin compiler doesn't know that, though.

169
00:07:46,010 --> 00:07:48,320
Kotlin's been designed to be a very safe language,

170
00:07:48,320 --> 00:07:51,130
and unless the compiler performed a thorough analysis of all

171
00:07:51,130 --> 00:07:54,290
the code, including all the code in the Android framework,

172
00:07:54,290 --> 00:07:56,860
there's no way it can tell that we're doing something safe.

173
00:07:56,860 --> 00:07:58,050
The Kotlin designers aren't going

174
00:07:58,050 --> 00:08:00,480
to add that sort of analysis to the compiler, it would

175
00:08:00,480 --> 00:08:03,850
increase compile time very significantly, for one thing.

176
00:08:03,850 --> 00:08:06,820
So it's up to us to deal with situations like this.

177
00:08:06,820 --> 00:08:08,620
So we could use the bang bang operator.

178
00:08:08,620 --> 00:08:11,710
We know that Task might be modified, so that's one approach.

179
00:08:11,710 --> 00:08:16,410
So if we come up here and add the bang bang operator,

180
00:08:16,410 --> 00:08:18,750
that clears the error and is one approach.

181
00:08:18,750 --> 00:08:20,270
We would have to do that for every line

182
00:08:20,270 --> 00:08:23,240
that the task appears in, so I prefer a different solution,

183
00:08:23,240 --> 00:08:26,100
and that's the solution I mentioned in an earlier video.

184
00:08:26,100 --> 00:08:28,640
Basically creating a local val variable

185
00:08:28,640 --> 00:08:30,630
and assigning Task to that.

186
00:08:30,630 --> 00:08:33,580
So let's do that, within the test for savedInstanceState

187
00:08:34,490 --> 00:08:38,633
being equal to null, val task equals task.

188
00:08:40,730 --> 00:08:42,480
So now the code block's referring to that

189
00:08:42,480 --> 00:08:46,350
local variable, not to the Task argument.

190
00:08:46,350 --> 00:08:48,450
Now we've also got a warning though over here now.

191
00:08:48,450 --> 00:08:50,250
From Android Studio, that the null,

192
00:08:50,250 --> 00:08:52,200
and we'll just go over it, hover over it.

193
00:08:52,200 --> 00:08:54,280
Basically unnecessary non-null assertion

194
00:08:54,280 --> 00:08:56,593
on a non-null receiver of type Task.

195
00:08:57,740 --> 00:09:00,190
So we can just remove the bang bang operator now,

196
00:09:01,380 --> 00:09:03,290
and that fixes that warning.

197
00:09:03,290 --> 00:09:04,730
But I've also got another warning here

198
00:09:04,730 --> 00:09:09,060
on line 54, about number formatting, and specifically,

199
00:09:09,060 --> 00:09:11,900
it doesn't take into account locale settings.

200
00:09:11,900 --> 00:09:13,910
If we were dealing with numbers that had decimal points,

201
00:09:13,910 --> 00:09:16,520
we would certainly take that warning seriously.

202
00:09:16,520 --> 00:09:18,330
Europe, for example, uses a comma

203
00:09:18,330 --> 00:09:20,250
instead of a dot for the decimal point,

204
00:09:20,250 --> 00:09:23,780
and a dot instead of a comma for the thousand separator.

205
00:09:23,780 --> 00:09:25,890
But here we're only dealing with integer values,

206
00:09:25,890 --> 00:09:27,770
without thousand separators, and there's

207
00:09:27,770 --> 00:09:31,440
no need to consider localization in this particular case.

208
00:09:31,440 --> 00:09:33,390
The easiest way to remove that warning

209
00:09:33,390 --> 00:09:36,070
is just to use the light bulb to suppress it.

210
00:09:36,070 --> 00:09:37,970
So depending on where you are on the line,

211
00:09:37,970 --> 00:09:39,620
we should be able to click into there,

212
00:09:39,620 --> 00:09:41,280
and the light bulb will appear,

213
00:09:41,280 --> 00:09:43,680
but it's very much depending on where you're clicking

214
00:09:43,680 --> 00:09:47,600
before we get the right way to suppress it.

215
00:09:47,600 --> 00:09:50,070
So I can click into the left parentheses,

216
00:09:50,070 --> 00:09:52,630
is usually a good option, and that now works.

217
00:09:52,630 --> 00:09:55,010
We've now got the suppress message come up,

218
00:09:55,010 --> 00:09:58,870
and we can click on that, and we get, on line 47,

219
00:09:58,870 --> 00:10:02,000
an annotation above the onViewCreated function,

220
00:10:02,000 --> 00:10:04,710
and that warning has now disappeared as a result.

221
00:10:04,710 --> 00:10:07,380
Alright, so that's the first part of the UI done.

222
00:10:07,380 --> 00:10:09,160
In the next video, we will need to

223
00:10:09,160 --> 00:10:11,620
add the code to the save button's listener

224
00:10:11,620 --> 00:10:14,110
to save the details to the database.

225
00:10:14,110 --> 00:10:15,410
See you in the next video.

