1
00:00:00,099 --> 00:00:02,836
(bright music)

2
00:00:02,836 --> 00:00:05,400
(typing)

3
00:00:05,400 --> 00:00:07,200
So we've nearly finished the user interface

4
00:00:07,200 --> 00:00:09,880
for adding and editing the task details.

5
00:00:09,880 --> 00:00:12,680
We've still gotta add the code though to save the data.

6
00:00:12,680 --> 00:00:13,740
Before we do that though,

7
00:00:13,740 --> 00:00:16,520
let's finish the code to display the fragment.

8
00:00:16,520 --> 00:00:19,210
At the moment, the user can't go back to the main screen

9
00:00:19,210 --> 00:00:21,450
without saving the data, which could be annoying

10
00:00:21,450 --> 00:00:24,660
if they've tapped the plus icon by mistake.

11
00:00:24,660 --> 00:00:26,680
We need to provide up navigation

12
00:00:26,680 --> 00:00:28,920
and also decide what we're going to do if the user

13
00:00:28,920 --> 00:00:32,460
taps the back button whilst they're editing a task.

14
00:00:32,460 --> 00:00:35,670
If an activity or fragment allows the user to navigate back,

15
00:00:35,670 --> 00:00:38,970
our users will expect an up button to appear in the toolbar.

16
00:00:38,970 --> 00:00:40,590
Android takes care of that for us

17
00:00:40,590 --> 00:00:43,810
if we pass true to the setDisplayAsHomeUpEnabled

18
00:00:43,810 --> 00:00:45,740
function or the action bar.

19
00:00:45,740 --> 00:00:47,730
Remember from the life cycle videos

20
00:00:47,730 --> 00:00:50,200
that a good place to modify the activity's UI

21
00:00:50,200 --> 00:00:53,900
is the fragment's onActivityCreated function.

22
00:00:53,900 --> 00:00:56,470
When that's called, the fragment knows that the activity's

23
00:00:56,470 --> 00:00:59,920
fully created and that it's layout has been inflated.

24
00:00:59,920 --> 00:01:01,594
So let's make a change there

25
00:01:01,594 --> 00:01:05,190
in our onActivityCreated function.

26
00:01:05,190 --> 00:01:08,810
Specifically we're gonna make a change here on line 49.

27
00:01:08,810 --> 00:01:11,227
I'm gonna type val actionBar equals

28
00:01:14,200 --> 00:01:18,980
parentheses listener as AppCompatActivity

29
00:01:20,360 --> 00:01:24,110
closing parentheses period supportActionBar.

30
00:01:25,683 --> 00:01:28,300
And the next line actionBar question mark

31
00:01:30,147 --> 00:01:33,170
dot setDisplayHomeAsUpEnabled parentheses true

32
00:01:35,470 --> 00:01:36,950
so adding that to the fragment code

33
00:01:36,950 --> 00:01:39,480
rather than setting the up button in the activity

34
00:01:39,480 --> 00:01:41,660
means that we don't have to worry about calling it

35
00:01:41,660 --> 00:01:43,410
whenever we display a new fragment.

36
00:01:43,410 --> 00:01:45,030
So that's pretty straightforward.

37
00:01:45,030 --> 00:01:47,740
We need a reference to the activity's action bar

38
00:01:47,740 --> 00:01:49,280
but it might not have one.

39
00:01:49,280 --> 00:01:51,280
And that's why we're using a safe call

40
00:01:51,280 --> 00:01:53,940
when calling setDisplayHomeAsUpEnabled.

41
00:01:53,940 --> 00:01:56,420
Obviously we can't show the up button in the toolbar

42
00:01:56,420 --> 00:01:57,750
if there isn't a toolbar

43
00:01:57,750 --> 00:01:59,980
but at least now the code won't crash.

44
00:01:59,980 --> 00:02:02,240
What's interesting here thought is the way we obtained

45
00:02:02,240 --> 00:02:05,270
a reference to the support action bar.

46
00:02:05,270 --> 00:02:07,740
This is a very easy mistake to make but it's wrong.

47
00:02:07,740 --> 00:02:10,763
So notice that listener is a nullable type.

48
00:02:10,763 --> 00:02:12,420
OnSaveClicked question mark

49
00:02:12,420 --> 00:02:14,120
so that means that it can be null.

50
00:02:15,340 --> 00:02:17,950
If we scroll up and have a look we can see

51
00:02:17,950 --> 00:02:20,960
we have defined our listener on line 30.

52
00:02:20,960 --> 00:02:22,376
That's in nullable type,

53
00:02:22,376 --> 00:02:24,326
we can see OnSaveClicked, question mark

54
00:02:26,750 --> 00:02:28,550
So that means that it can be null

55
00:02:28,550 --> 00:02:30,620
and we've seen that fragment's activity isn't

56
00:02:30,620 --> 00:02:33,540
always available in the fragment life cycle.

57
00:02:33,540 --> 00:02:36,890
So we're adding this code in the onActivityCreated function

58
00:02:36,890 --> 00:02:40,660
so it's almost certainly safe to do what we've done here.

59
00:02:40,660 --> 00:02:42,340
onActivityCreated won't get called

60
00:02:42,340 --> 00:02:44,990
unless the fragments activity is available.

61
00:02:44,990 --> 00:02:47,900
Even so, I'd advice against doing this.

62
00:02:47,900 --> 00:02:50,650
We've cast listener to appCompatActivity

63
00:02:50,650 --> 00:02:52,780
which it will be if it has an action bar

64
00:02:52,780 --> 00:02:55,700
but we should've specified the nullable type.

65
00:02:55,700 --> 00:02:58,530
In other words appCompactActivity question mark.

66
00:02:58,530 --> 00:03:00,550
As I said though it should be fine in here

67
00:03:00,550 --> 00:03:02,960
we're unlikely to detach from the activity

68
00:03:02,960 --> 00:03:05,470
while onActivityCreated is running.

69
00:03:05,470 --> 00:03:07,400
But the correct code would actually be

70
00:03:07,400 --> 00:03:09,900
to add a question mark after appCompatActivity

71
00:03:12,090 --> 00:03:13,520
and outside of the parentheses

72
00:03:13,520 --> 00:03:15,990
to add a second question mark.

73
00:03:15,990 --> 00:03:18,363
So I'm making one unnullable type making appCompatActivity

74
00:03:18,363 --> 00:03:21,630
a nullable type now and also using a safe call

75
00:03:21,630 --> 00:03:23,780
to support action bar.

76
00:03:23,780 --> 00:03:26,740
So remember that we're showing general techniques here.

77
00:03:26,740 --> 00:03:29,010
Although that would almost certainly have been fine

78
00:03:29,010 --> 00:03:30,106
before I changed it, you may wanna do

79
00:03:30,106 --> 00:03:32,820
something similar somewhere else.

80
00:03:32,820 --> 00:03:35,740
Like inside onActivityCreated in other words.

81
00:03:35,740 --> 00:03:38,650
The thing to take away from this is that Android Studio

82
00:03:38,650 --> 00:03:42,530
and the Kotlin code checker can only help you so much.

83
00:03:42,530 --> 00:03:45,480
If you specify a cast to a non nullable type

84
00:03:45,480 --> 00:03:48,910
then the checker won't warn you to use a safe call.

85
00:03:48,910 --> 00:03:51,340
If you're casting something that could be null

86
00:03:51,340 --> 00:03:53,910
make sure you use a nullable type in the cast

87
00:03:53,910 --> 00:03:57,580
otherwise your code will crash if it attempts to cast null

88
00:03:57,580 --> 00:03:59,120
to any other type.

89
00:03:59,120 --> 00:04:01,730
Technically it might be possible for the checker

90
00:04:01,730 --> 00:04:03,820
to have detected the problem with the cast

91
00:04:03,820 --> 00:04:05,500
so if you get slightly different behaviour

92
00:04:05,500 --> 00:04:07,440
and did see a warning, then that's fine,

93
00:04:07,440 --> 00:04:09,520
things are changing all the time.

94
00:04:09,520 --> 00:04:10,353
Alright so moving on,

95
00:04:10,353 --> 00:04:13,550
next we should really make sure that the cast will succeed.

96
00:04:13,550 --> 00:04:16,380
So let's go ahead and make a change for that.

97
00:04:16,380 --> 00:04:19,120
So I'm going to type if parentheses

98
00:04:19,120 --> 00:04:24,120
listener is AppCompatActivity, closing parentheses

99
00:04:25,608 --> 00:04:27,710
I'm gonna open a code block, left curly brace

100
00:04:27,710 --> 00:04:29,610
and I left the right curly brace below

101
00:04:30,759 --> 00:04:33,770
the set call to setDisplayAsHomeUpEnabled

102
00:04:33,770 --> 00:04:35,840
and then add a line space there.

103
00:04:35,840 --> 00:04:38,760
Now if you use the fragment from a fragment activity

104
00:04:38,760 --> 00:04:41,120
for example it won't crash.

105
00:04:41,120 --> 00:04:43,820
A fragment activity doesn't have to have an action bar

106
00:04:43,820 --> 00:04:46,500
and without this test that code would have crashed.

107
00:04:46,500 --> 00:04:48,410
Because one of the reasons for using a fragment

108
00:04:48,410 --> 00:04:51,050
is so that it can be reused, you shouldn't be making

109
00:04:51,050 --> 00:04:53,770
assumptions about what will be reusing it.

110
00:04:53,770 --> 00:04:56,390
Alright so a brief digression next,

111
00:04:56,390 --> 00:04:58,730
you might be wondering why we can't let Kotlin

112
00:04:58,730 --> 00:05:00,810
perform a safe cast here.

113
00:05:00,810 --> 00:05:03,503
So what I might need is I'm gonna duplicate this line.

114
00:05:05,680 --> 00:05:07,470
I'm gonna comment one out.

115
00:05:07,470 --> 00:05:08,520
So why can't we just do this

116
00:05:08,520 --> 00:05:10,890
so val actionBar equals

117
00:05:12,720 --> 00:05:13,890
I'll just delete the whole, it'll be quicker,

118
00:05:13,890 --> 00:05:15,760
listener.supportActionBar.

119
00:05:18,410 --> 00:05:20,170
Why can't we do that?

120
00:05:20,170 --> 00:05:21,440
Because now we've already checked

121
00:05:21,440 --> 00:05:22,840
that listener isn't null, haven't we?

122
00:05:22,840 --> 00:05:26,470
If it is an appCompatActivity then surely it can't be null?

123
00:05:26,470 --> 00:05:28,380
Well, unfortunately things don't work like that

124
00:05:28,380 --> 00:05:30,320
in a multi-threaded environment

125
00:05:30,320 --> 00:05:31,800
and the error message will confirm that

126
00:05:31,800 --> 00:05:33,270
if I hover over it.

127
00:05:33,270 --> 00:05:35,060
So my cast to appCompatActivity

128
00:05:35,060 --> 00:05:38,510
is impossible because the listener is a mutual property

129
00:05:38,510 --> 00:05:41,200
that could have changed by this time.

130
00:05:41,200 --> 00:05:43,430
We may know that it can't change between our test

131
00:05:43,430 --> 00:05:46,010
and when we get to its supportActionBar,

132
00:05:46,010 --> 00:05:48,460
but there's no way for the compiler to know that.

133
00:05:48,460 --> 00:05:50,160
The compiler isn't aware of the environment

134
00:05:50,160 --> 00:05:51,250
that our code's running in,

135
00:05:51,250 --> 00:05:53,670
it just complies Kotlin code.

136
00:05:53,670 --> 00:05:56,300
Unless it can determine that a smart cast

137
00:05:56,300 --> 00:05:59,010
will always succeed, it won't actually allow one.

138
00:05:59,010 --> 00:06:00,630
And there's been some discussion of this

139
00:06:00,630 --> 00:06:04,190
at kotlinlang.org, and I have a quick read,

140
00:06:04,190 --> 00:06:05,160
I'm just gonna quickly bring that up

141
00:06:05,160 --> 00:06:07,563
on the screen so you've got access to the link.

142
00:06:10,920 --> 00:06:12,580
So, check out this article and have a bit of a read

143
00:06:12,580 --> 00:06:13,870
about that if you're interested in some

144
00:06:13,870 --> 00:06:17,840
of the technical reasons why things work this way.

145
00:06:17,840 --> 00:06:19,790
So, I'm mentioning this now because there's a trick

146
00:06:19,790 --> 00:06:21,900
that we can use to get around the problem,

147
00:06:21,900 --> 00:06:26,540
now go back to our code, so what we can do

148
00:06:26,540 --> 00:06:29,030
is assign listener to a local val

149
00:06:29,030 --> 00:06:30,740
and use that instead.

150
00:06:30,740 --> 00:06:34,260
So, come up here and type val listener

151
00:06:35,290 --> 00:06:36,983
is equal to listener.

152
00:06:38,660 --> 00:06:40,460
So now the compiler can be sure

153
00:06:40,460 --> 00:06:42,300
that the local listener can't be modified

154
00:06:42,300 --> 00:06:46,170
anywhere else and performs the smart cast.

155
00:06:46,170 --> 00:06:48,940
And you can see now that listener on line 52

156
00:06:48,940 --> 00:06:51,750
is highlighted in green to show that a smart cast

157
00:06:51,750 --> 00:06:53,850
is being performed, if you hover over that

158
00:06:55,860 --> 00:06:58,130
we can see confirmation of that.

159
00:06:58,130 --> 00:06:59,890
There's no problem having a local variable

160
00:06:59,890 --> 00:07:02,420
with the same name as the class variable, by the way.

161
00:07:02,420 --> 00:07:05,960
The local variable will be used once its declared.

162
00:07:05,960 --> 00:07:07,370
Alright, so, we're using that technique

163
00:07:07,370 --> 00:07:09,570
a little later, here we're only accessing

164
00:07:09,570 --> 00:07:13,080
a single attribute of the listener in one place

165
00:07:13,080 --> 00:07:15,930
so I prefer to use a nullable type and safe call.

166
00:07:15,930 --> 00:07:17,930
So that only involves typing two question marks

167
00:07:17,930 --> 00:07:19,800
rather than the entire line.

168
00:07:19,800 --> 00:07:21,410
We'll see this technique being used later

169
00:07:21,410 --> 00:07:24,633
but for now that I'm gonna do is undo those changes.

170
00:07:33,271 --> 00:07:34,800
And back to how we had it there.

171
00:07:34,800 --> 00:07:36,070
And again, my preference is to use

172
00:07:36,070 --> 00:07:37,710
a nullable type and safe call,

173
00:07:37,710 --> 00:07:40,100
and as you see that involves typing two question marks

174
00:07:40,100 --> 00:07:42,290
rather than the entire line.

175
00:07:42,290 --> 00:07:44,340
Alright, so the next video, recap of how an object

176
00:07:44,340 --> 00:07:47,400
can be of more than one type at the same time.

177
00:07:47,400 --> 00:07:48,700
See you in the next video.

