1
00:00:05,440 --> 00:00:06,689
Alright, so let's continue on now

2
00:00:06,689 --> 00:00:09,120
updating our application, our calculator app.

3
00:00:09,120 --> 00:00:12,150
Back in MainActivity, our first OnClickListener

4
00:00:12,150 --> 00:00:14,800
is appending the button's caption

5
00:00:14,800 --> 00:00:17,600
to the edit text widget's contents.

6
00:00:17,600 --> 00:00:19,770
So, that's at the start of onCreate.

7
00:00:19,770 --> 00:00:23,350
You can see it doing that lines 15 through 18.

8
00:00:23,350 --> 00:00:25,140
So, the new number widget's going to

9
00:00:25,140 --> 00:00:26,340
have its values set from our

10
00:00:26,340 --> 00:00:29,920
view model's LiveData object instead.

11
00:00:29,920 --> 00:00:32,500
So what we need to do here is call a function

12
00:00:32,500 --> 00:00:34,660
in the view model to tell it that

13
00:00:34,660 --> 00:00:37,200
a digit button was tapped.

14
00:00:37,200 --> 00:00:39,800
I'm gonna call the function digitPressed

15
00:00:39,800 --> 00:00:42,960
and we'll be pasting the button's caption as an argument.

16
00:00:42,960 --> 00:00:44,027
We haven't written it yet, so we're gonna

17
00:00:44,027 --> 00:00:46,170
get an error when I actually do this,

18
00:00:46,170 --> 00:00:48,040
in fact we'll get two errors because

19
00:00:48,040 --> 00:00:50,400
we haven't subscribed to the view model yet.

20
00:00:50,400 --> 00:00:51,970
But one thing at a time,

21
00:00:51,970 --> 00:00:54,720
so what we're gonna do first is delete these two lines,

22
00:00:56,266 --> 00:00:59,160
we're gonna replace that with viewModel

23
00:00:59,160 --> 00:01:01,823
which again, we haven't defined yet, .digitPressed.

24
00:01:04,971 --> 00:01:07,477
Then we need two parentheses, v as Button,

25
00:01:09,000 --> 00:01:13,443
closing parentheses, .text.toString,

26
00:01:14,840 --> 00:01:16,740
then we've got the closing parentheses

27
00:01:17,978 --> 00:01:20,240
for toString and the closing parentheses for that line.

28
00:01:20,240 --> 00:01:22,690
I'm tempted to modify the other two listeners

29
00:01:22,690 --> 00:01:24,410
to avoid jumping back and forth between

30
00:01:24,410 --> 00:01:26,740
our two classes, but I think it's clearer

31
00:01:26,740 --> 00:01:28,860
if we stick to one thing at a time.

32
00:01:28,860 --> 00:01:31,250
So let's write the digitPressed function

33
00:01:31,250 --> 00:01:33,760
in CalculatorViewModel next.

34
00:01:33,760 --> 00:01:36,520
We'll go back to the CalculatorViewModel class

35
00:01:36,520 --> 00:01:38,140
and I'm gonna put this before

36
00:01:38,140 --> 00:01:39,823
the perform operation function.

37
00:01:40,760 --> 00:01:43,823
So I'm gonna start by typing fun digitPressed,

38
00:01:45,280 --> 00:01:48,083
parentheses, caption: String.

39
00:01:50,443 --> 00:01:51,920
And the terms of the code,

40
00:01:51,920 --> 00:01:53,740
you're gonna start by putting if,

41
00:01:53,740 --> 00:01:57,790
parentheses, newNumber.value

42
00:01:58,710 --> 00:02:01,790
is not equal to null, closing parentheses.

43
00:02:01,790 --> 00:02:04,712
We'll open a code block, then we're gonna type

44
00:02:04,712 --> 00:02:09,673
newNumber.value is equal to newNumber.value

45
00:02:12,330 --> 00:02:14,980
plus caption, and we'll need to add

46
00:02:14,980 --> 00:02:16,580
an else to that code block,

47
00:02:16,580 --> 00:02:19,089
else gets its own code block,

48
00:02:19,089 --> 00:02:23,473
newNumber.value is equal to caption.

49
00:02:25,000 --> 00:02:26,350
I've effectively, digitPressed,

50
00:02:26,350 --> 00:02:28,700
that's this digitPressed function.

51
00:02:28,700 --> 00:02:30,640
It does the same thing as the code

52
00:02:30,640 --> 00:02:32,230
we've removed from MainActivity.

53
00:02:32,230 --> 00:02:34,080
It appends the button's caption

54
00:02:34,080 --> 00:02:38,160
to the current value of a newNumber LiveData object.

55
00:02:38,160 --> 00:02:39,860
We do need a null check there that we've got

56
00:02:39,860 --> 00:02:43,100
on line 20 because value may well be null.

57
00:02:43,100 --> 00:02:45,620
If we don't check for null, we'll get the string null

58
00:02:45,620 --> 00:02:47,640
appearing at the start of our number.

59
00:02:47,640 --> 00:02:49,900
Alright, so back to MainActivity,

60
00:02:49,900 --> 00:02:52,870
and let's now look for, or look at, the next listener.

61
00:02:52,870 --> 00:02:55,970
This next listener is the listener

62
00:02:55,970 --> 00:02:59,660
that responds to one of the operand buttons being tapped.

63
00:02:59,660 --> 00:03:01,640
We'll do something similar here.

64
00:03:01,640 --> 00:03:03,930
We'll call a function in the view model

65
00:03:03,930 --> 00:03:06,560
and pass it the caption of the button.

66
00:03:06,560 --> 00:03:08,010
There's a lot more code in this function

67
00:03:08,010 --> 00:03:09,640
so instead of deleting it, what I'm going to do

68
00:03:09,640 --> 00:03:11,760
is cut it to the clipboard.

69
00:03:11,760 --> 00:03:13,460
That'll save typing when we create

70
00:03:13,460 --> 00:03:16,490
the corresponding function in the view model.

71
00:03:16,490 --> 00:03:20,142
What I'm going to do first is the OnClickListener,

72
00:03:20,142 --> 00:03:20,975
that's the first line there,

73
00:03:20,975 --> 00:03:24,190
I'm going to type viewModel, which again

74
00:03:24,190 --> 00:03:26,390
we haven't yet defined, the function

75
00:03:26,390 --> 00:03:28,433
will be called operandPressed,

76
00:03:29,990 --> 00:03:31,940
which again we haven't created yet,

77
00:03:31,940 --> 00:03:35,170
two parentheses, v as Button,

78
00:03:35,170 --> 00:03:38,383
closing parentheses, .text.toString.

79
00:03:40,000 --> 00:03:40,940
We've got the two parentheses,

80
00:03:40,940 --> 00:03:43,340
to close off toString and then the parentheses

81
00:03:43,340 --> 00:03:47,860
to close off the operandPressed function call.

82
00:03:47,860 --> 00:03:49,270
I'm gonna copy the rest of this text

83
00:03:49,270 --> 00:03:53,140
or rather, cut this text out of this listener

84
00:03:53,140 --> 00:03:54,810
as mentioned, and we're gonna go back

85
00:03:54,810 --> 00:03:57,480
to our CalculatorViewModel class.

86
00:03:57,480 --> 00:03:59,730
We're gonna write the operandPressed function.

87
00:03:59,730 --> 00:04:03,093
I'm gonna put that below the digitPressed function.

88
00:04:04,700 --> 00:04:07,860
We'll start by typing fun, that's operandPressed.

89
00:04:09,690 --> 00:04:13,750
It's got op called String, parentheses,

90
00:04:13,750 --> 00:04:15,770
and you have to write curly braces

91
00:04:15,770 --> 00:04:17,680
to make it a function and we'll paste in

92
00:04:17,680 --> 00:04:20,829
that code from our MainActivity class.

93
00:04:20,829 --> 00:04:22,260
Once again here, we want to make sure

94
00:04:22,260 --> 00:04:25,010
we click cancel when asked to import

95
00:04:25,010 --> 00:04:28,770
the synthetic imports, so I'm going to cancel that.

96
00:04:28,770 --> 00:04:30,420
The reason is firstly, we don't need

97
00:04:30,420 --> 00:04:31,990
that first line because we're not

98
00:04:31,990 --> 00:04:34,390
going to be dealing with the UI.

99
00:04:34,390 --> 00:04:36,090
Alright, so I'm gonna cancel that.

100
00:04:38,450 --> 00:04:40,550
Firstly, this first line here,

101
00:04:40,550 --> 00:04:42,310
we don't actually need that because

102
00:04:42,310 --> 00:04:44,610
we've already cast the view to be a button

103
00:04:44,610 --> 00:04:46,960
and passed its text already as the op argument

104
00:04:46,960 --> 00:04:48,210
so I'm gonna delete that.

105
00:04:49,400 --> 00:04:51,480
There are a couple of things to fix though.

106
00:04:51,480 --> 00:04:54,090
Firstly, newNumber, which we're using here

107
00:04:54,090 --> 00:04:57,380
on line 30 is a LiveData object in here

108
00:04:57,380 --> 00:05:00,937
so we need to get its value rather than its text.

109
00:05:00,937 --> 00:05:02,860
I'm gonna change text there to value

110
00:05:04,610 --> 00:05:06,723
but also with a safe call operator.

111
00:05:08,071 --> 00:05:09,571
I'm gonna remove the .toString

112
00:05:10,783 --> 00:05:13,730
and call .toDouble instead.

113
00:05:13,730 --> 00:05:15,221
That's the first part, then down here

114
00:05:15,221 --> 00:05:19,090
where it's newNumber.setText,

115
00:05:19,090 --> 00:05:21,140
we need to change that to value as well,

116
00:05:21,140 --> 00:05:22,890
equals, and get rid of the parentheses

117
00:05:22,890 --> 00:05:24,940
around the two double quotes.

118
00:05:24,940 --> 00:05:27,840
It's possible that newNumber may not have a value,

119
00:05:27,840 --> 00:05:29,410
which is why we're using a safe call,

120
00:05:29,410 --> 00:05:31,240
why I added a safe call before

121
00:05:31,240 --> 00:05:33,970
converting it to a double on line 30.

122
00:05:33,970 --> 00:05:36,500
As a result, I've got an error here, when we try

123
00:05:36,500 --> 00:05:39,797
and pass value to the performOperation function.

124
00:05:39,797 --> 00:05:42,700
Value is actually a nullable double

125
00:05:42,700 --> 00:05:45,310
and pendingOperation expects a non-null argument.

126
00:05:45,310 --> 00:05:47,890
What we can do to resolve this

127
00:05:47,890 --> 00:05:50,000
is wrap the call in a null test

128
00:05:50,000 --> 00:05:52,870
and let Kotlin perform a smart cast for us.

129
00:05:52,870 --> 00:05:57,070
To do that, after the value line on 30,

130
00:05:57,070 --> 00:05:59,250
I'm gonna put if, parentheses,

131
00:05:59,250 --> 00:06:01,133
value is not equal to null,

132
00:06:02,519 --> 00:06:04,380
open a code block, I'm gonna paste in

133
00:06:04,380 --> 00:06:08,310
that performOperation into that code block.

134
00:06:08,310 --> 00:06:09,530
The last change to this function

135
00:06:09,530 --> 00:06:11,250
is similar to what we've done earlier.

136
00:06:11,250 --> 00:06:12,830
We're attempting to now update

137
00:06:12,830 --> 00:06:14,930
the operation widget and we should

138
00:06:14,930 --> 00:06:18,130
actually be using another LiveData object instead.

139
00:06:18,130 --> 00:06:21,140
Let's declare that LiveData object

140
00:06:21,140 --> 00:06:23,440
below the other two, so we're going to need

141
00:06:23,440 --> 00:06:25,510
a val here for operation, val operation

142
00:06:26,440 --> 00:06:30,333
is equal to, it's also a MutableLiveData object.

143
00:06:31,170 --> 00:06:33,090
It's a string, you'll have to write in

144
00:06:33,090 --> 00:06:34,880
less than and greater than signs,

145
00:06:34,880 --> 00:06:37,770
and add parentheses as well.

146
00:06:37,770 --> 00:06:39,340
Then once we've done that, we can change

147
00:06:39,340 --> 00:06:43,540
this operation.text to operation.value

148
00:06:44,710 --> 00:06:47,253
to save it to our MutableLiveData object.

149
00:06:48,500 --> 00:06:51,090
Okay, just clean up some lines here.

150
00:06:51,090 --> 00:06:53,110
Alright, so that's two listeners changed.

151
00:06:53,110 --> 00:06:54,760
There's one more listener we need to change.

152
00:06:54,760 --> 00:06:56,260
Let's go back to MainActivity.

153
00:06:57,360 --> 00:07:00,406
This third listener that we need to change.

154
00:07:00,406 --> 00:07:01,850
You're gonna do the same pressers here,

155
00:07:01,850 --> 00:07:03,460
add a call to the appropriate function

156
00:07:03,460 --> 00:07:05,670
in the view model, and cut the code out of here

157
00:07:05,670 --> 00:07:07,500
and paste it into the new function

158
00:07:07,500 --> 00:07:10,962
in our CalculatorViewModel.

159
00:07:10,962 --> 00:07:13,587
Within the buttonNeg.setOnClickListener,

160
00:07:13,587 --> 00:07:18,493
I'm gonna do a call to viewModel.negPressed,

161
00:07:19,580 --> 00:07:22,153
parentheses, of course we getting errors

162
00:07:22,153 --> 00:07:23,760
because it hasn't been created yet.

163
00:07:23,760 --> 00:07:25,713
We're gonna cut out this code,

164
00:07:28,103 --> 00:07:30,400
we're gonna go back to our CalculatorViewModel class

165
00:07:30,400 --> 00:07:32,680
and let's add this function below the other two,

166
00:07:32,680 --> 00:07:36,890
below the digitPressed and operandPressed functions.

167
00:07:36,890 --> 00:07:41,890
This one is negPressed, no parameters for this one.

168
00:07:43,330 --> 00:07:44,530
We'll paste in the code.

169
00:07:45,830 --> 00:07:47,560
Once again, I'm gonna cancel the suggestion

170
00:07:47,560 --> 00:07:49,083
to add the synthetic import.

171
00:07:50,020 --> 00:07:52,690
We'll just move this up so I can see a bit easier.

172
00:07:52,690 --> 00:07:54,720
Fixing the errors, it's the same as before.

173
00:07:54,720 --> 00:07:57,900
We just need to use the value property instead of text.

174
00:07:57,900 --> 00:07:58,870
It's pretty easy there because

175
00:07:58,870 --> 00:08:00,990
all the references there are actually

176
00:08:00,990 --> 00:08:03,200
highlighted in red for us, so firstly

177
00:08:03,200 --> 00:08:08,200
newNumber.text is newNumber.value, delete that out.

178
00:08:08,630 --> 00:08:12,223
NewNumber.setText, change that to value.

179
00:08:14,371 --> 00:08:16,440
That's gonna be equal to, remove the parentheses

180
00:08:16,440 --> 00:08:19,510
around the double quotes and minus sign.

181
00:08:19,510 --> 00:08:22,507
Next we've got newNumber.setText.

182
00:08:22,507 --> 00:08:24,657
We're gonna change that to newNumber.value.

183
00:08:25,570 --> 00:08:27,600
That's gonna be equal now to,

184
00:08:27,600 --> 00:08:30,600
remove the parentheses from doubleValue.toString.

185
00:08:30,600 --> 00:08:33,890
You've still got the parentheses on the end of toString.

186
00:08:33,890 --> 00:08:36,775
Finally, to catch the NumberFormatException,

187
00:08:36,775 --> 00:08:39,429
newNumber, instead of .text, it's .value

188
00:08:40,530 --> 00:08:43,000
equals, remove the parentheses,

189
00:08:43,000 --> 00:08:44,830
and leave the double quotes in there.

190
00:08:44,830 --> 00:08:47,760
You can see that we've still got an error here though.

191
00:08:47,760 --> 00:08:50,590
This error here, we're calling the isEmpty function

192
00:08:50,590 --> 00:08:52,520
on something that may be null.

193
00:08:52,520 --> 00:08:53,780
But this particular scenario,

194
00:08:53,780 --> 00:08:55,650
rather than using a safe call,

195
00:08:55,650 --> 00:08:57,500
I'm going to add a null check.

196
00:08:57,500 --> 00:09:00,260
The reason is that Kotlin can't perform

197
00:09:00,260 --> 00:09:02,920
a safe cast on this line down here,

198
00:09:02,920 --> 00:09:05,520
this value.toDouble, so it's also showing

199
00:09:05,520 --> 00:09:06,940
an error there for that reason,

200
00:09:06,940 --> 00:09:09,630
but a null check will fix that error as well.

201
00:09:09,630 --> 00:09:10,890
What we need to do is change this line,

202
00:09:10,890 --> 00:09:13,800
it's currently got if parentheses value.isEmpty.

203
00:09:13,800 --> 00:09:15,090
We'll add a null check in there.

204
00:09:15,090 --> 00:09:20,090
If value is equal to null or value.isEmpty,

205
00:09:21,100 --> 00:09:23,960
or, that's two pipe characters,

206
00:09:23,960 --> 00:09:26,183
that then fixes the remaining errors.

207
00:09:27,110 --> 00:09:30,120
That's our viewModel class finished for now anyway.

208
00:09:30,120 --> 00:09:31,630
We're gonna come back to it to sort out

209
00:09:31,630 --> 00:09:33,010
that problem that I mentioned.

210
00:09:33,010 --> 00:09:34,700
We shouldn't really be exposing

211
00:09:34,700 --> 00:09:36,810
MutableLiveData objects but we'll see

212
00:09:36,810 --> 00:09:39,710
how to deal with that once we've got the app working.

213
00:09:39,710 --> 00:09:41,493
Before leaving though, just make a check here.

214
00:09:41,493 --> 00:09:43,470
Just make sure that the imports,

215
00:09:43,470 --> 00:09:45,620
or check the imports rather, to make sure

216
00:09:45,620 --> 00:09:48,080
that there's no synthetic imports hanging around.

217
00:09:48,080 --> 00:09:51,450
You can see in my case that there's no imports there.

218
00:09:51,450 --> 00:09:52,720
The last thing we now need to do

219
00:09:52,720 --> 00:09:57,508
is to subscribe MainActivity to our CalculatorViewModel.

220
00:09:57,508 --> 00:10:00,540
Going back to MainActivity and specifically in

221
00:10:00,540 --> 00:10:03,290
the onCreate function, we're going to

222
00:10:03,290 --> 00:10:05,832
use the viewModelProviders class

223
00:10:05,832 --> 00:10:07,846
to get a reference to the view model.

224
00:10:07,846 --> 00:10:08,950
This code I'm about to type in

225
00:10:08,950 --> 00:10:10,070
is lifted straight out of that

226
00:10:10,070 --> 00:10:12,940
example code we were looking at earlier.

227
00:10:12,940 --> 00:10:14,090
Just as a warning, we'll actually

228
00:10:14,090 --> 00:10:16,670
get an error as we go through this.

229
00:10:16,670 --> 00:10:18,620
If I type in, below the setContentView,

230
00:10:20,476 --> 00:10:24,927
val viewModel is equal to ViewModelProviders.

231
00:10:26,720 --> 00:10:28,323
I actually want providers here,

232
00:10:29,510 --> 00:10:32,260
but notice we haven't got an option for providers.

233
00:10:32,260 --> 00:10:34,030
We want providers and not provider

234
00:10:34,030 --> 00:10:35,550
but that doesn't appear in the suggestions

235
00:10:35,550 --> 00:10:37,130
but we'll see why in a moment.

236
00:10:37,130 --> 00:10:38,280
I'm gonna continue typing this.

237
00:10:38,280 --> 00:10:42,633
Providers.of, parentheses, this, parentheses,

238
00:10:43,507 --> 00:10:45,490
.get, then in parentheses again,

239
00:10:45,490 --> 00:10:50,490
it's gonna be CalculatorViewModel::class.java, parentheses.

240
00:10:53,060 --> 00:10:54,410
The only difference to the code

241
00:10:54,410 --> 00:10:57,790
in the example is that we used ::class.java

242
00:10:57,790 --> 00:10:59,807
rather than .class because this is Kotlin

243
00:10:59,807 --> 00:11:03,590
and the example we were looking at earlier is in Java.

244
00:11:03,590 --> 00:11:05,220
Well, there's actually another difference,

245
00:11:05,220 --> 00:11:06,630
we've got an error at the moment,

246
00:11:06,630 --> 00:11:08,200
so switching back to that document,

247
00:11:08,200 --> 00:11:10,470
go back to our browser again.

248
00:11:10,470 --> 00:11:11,510
We'll have a look at the top left here.

249
00:11:11,510 --> 00:11:13,540
There's this sub option here,

250
00:11:13,540 --> 00:11:15,680
adding components to your project.

251
00:11:15,680 --> 00:11:17,300
I'm gonna click on that.

252
00:11:17,300 --> 00:11:19,610
That's gonna open up another page.

253
00:11:19,610 --> 00:11:21,693
If you scroll down and have a bit of a look there,

254
00:11:23,800 --> 00:11:25,280
you can see lifecycle, we've got some

255
00:11:25,280 --> 00:11:28,630
information there about dependencies

256
00:11:28,630 --> 00:11:32,200
that are needed for LiveData, lifecycle, and ViewModel.

257
00:11:32,200 --> 00:11:33,520
We haven't actually done this step yet

258
00:11:33,520 --> 00:11:35,170
and that's why we didn't get the suggestion

259
00:11:35,170 --> 00:11:38,010
in the drop down and why we've got an error.

260
00:11:38,010 --> 00:11:39,530
We need to actually follow the advice here

261
00:11:39,530 --> 00:11:42,730
and add the appropriate things to our build.gradle file.

262
00:11:42,730 --> 00:11:44,280
Now, I could have referred you

263
00:11:44,280 --> 00:11:46,423
to this link first and avoided the errors

264
00:11:46,423 --> 00:11:48,438
but it's such an easy thing to forget

265
00:11:48,438 --> 00:11:50,410
that seeing what happens when you do forget,

266
00:11:50,410 --> 00:11:52,390
I think, is very useful.

267
00:11:52,390 --> 00:11:54,190
I scroll down as you saw and a little way

268
00:11:54,190 --> 00:11:56,300
down that page you can see this lifecycle section.

269
00:11:56,300 --> 00:11:59,860
We want ViewModel and LiveData

270
00:11:59,860 --> 00:12:01,890
and you can see that's the top dependency here.

271
00:12:01,890 --> 00:12:03,270
What we need to do again, as I mentioned,

272
00:12:03,270 --> 00:12:05,720
is add to our build.gradle file.

273
00:12:05,720 --> 00:12:07,854
Google started spreading the version numbers out

274
00:12:07,854 --> 00:12:10,140
so here you can see that they've defined

275
00:12:10,140 --> 00:12:14,770
the lifecycle version to be 1.1.1 at the moment

276
00:12:14,770 --> 00:12:16,810
as of the time I'm recording this.

277
00:12:16,810 --> 00:12:18,330
We're gonna copy these three lines,

278
00:12:18,330 --> 00:12:20,330
starting from the def lifecycle_version,

279
00:12:21,195 --> 00:12:22,520
including the comment, and including this

280
00:12:22,520 --> 00:12:24,760
next line, the implementation line.

281
00:12:24,760 --> 00:12:27,440
We'll take a copy of that and we want to

282
00:12:27,440 --> 00:12:31,199
actually go back to our module's build.gradle file.

283
00:12:31,199 --> 00:12:36,199
So I'll open up that, click on our module app.

284
00:12:37,551 --> 00:12:40,240
I'm gonna double click on the build.gradle file.

285
00:12:41,465 --> 00:12:45,090
What we're going to do is paste in those three lines

286
00:12:45,090 --> 00:12:47,520
as the first entry below the dependencies,

287
00:12:47,520 --> 00:12:49,470
or in the dependencies section.

288
00:12:49,470 --> 00:12:52,030
Using that lifecycle_version declaration,

289
00:12:52,030 --> 00:12:53,570
I think, makes it much easier to

290
00:12:53,570 --> 00:12:56,580
update the version of all lifecycle dependencies

291
00:12:56,580 --> 00:12:59,950
at once rather than hunting through the list to find them.

292
00:12:59,950 --> 00:13:01,322
While we're here though, we've also got

293
00:13:01,322 --> 00:13:02,790
this other warning which we've seen

294
00:13:02,790 --> 00:13:06,917
in other projects that the Kotlin-stdlib-jre is deprecated

295
00:13:08,700 --> 00:13:11,500
and should be replaced with jdk instead.

296
00:13:11,500 --> 00:13:13,050
At the moment, Android Studio is still

297
00:13:13,050 --> 00:13:16,520
generating new projects with that deprecated dependency

298
00:13:16,520 --> 00:13:17,820
and they're obviously going to change

299
00:13:17,820 --> 00:13:20,223
at some point so if you don't see this warning,

300
00:13:20,223 --> 00:13:22,750
then you can ignore this bit, that's fine.

301
00:13:22,750 --> 00:13:25,260
But I'll update the deprecated dependency

302
00:13:25,260 --> 00:13:26,093
which is easy to spot because it's got

303
00:13:26,093 --> 00:13:28,040
a line striking it out.

304
00:13:28,040 --> 00:13:30,270
I'm gonna change, we're gonna delete the re

305
00:13:30,270 --> 00:13:34,570
in jre and change that with jdk and we need

306
00:13:34,570 --> 00:13:38,620
to sync now and that should have fixed the error.

307
00:13:38,620 --> 00:13:40,560
It also removed the warning,

308
00:13:40,560 --> 00:13:42,190
so I'll wait for that to finish,

309
00:13:42,190 --> 00:13:44,290
then we'll go back and check MainActivity.

310
00:13:45,970 --> 00:13:48,660
You can see that it was downloading some components.

311
00:13:48,660 --> 00:13:53,370
It's actually now synced and we can close down that window.

312
00:13:53,370 --> 00:13:56,180
You can see we've no longer got a warning there after jdk.

313
00:13:56,180 --> 00:13:57,850
If you go back to MainActivity,

314
00:13:57,850 --> 00:13:59,850
we've now got an option there to import.

315
00:14:00,760 --> 00:14:01,593
It may come up automatically or

316
00:14:01,593 --> 00:14:03,220
you may need to import it yourself.

317
00:14:04,380 --> 00:14:06,300
Once you do that, you can see that

318
00:14:06,300 --> 00:14:08,580
we've now got ViewModelProviders being valid.

319
00:14:08,580 --> 00:14:09,520
You can see the import has now

320
00:14:09,520 --> 00:14:11,263
been added onto line 3 as well.

321
00:14:12,130 --> 00:14:14,550
Now, often that'll actually auto-import

322
00:14:14,550 --> 00:14:17,470
for you automatically, but you can see

323
00:14:17,470 --> 00:14:19,870
in my case I needed to do an Alt + Enter

324
00:14:19,870 --> 00:14:21,790
to import ViewModelProviders

325
00:14:21,790 --> 00:14:24,210
from Android.arch.lifecycle.

326
00:14:24,210 --> 00:14:27,267
Just do that if it doesn't import automatically.

327
00:14:27,267 --> 00:14:28,270
Now that we've actually imported that,

328
00:14:28,270 --> 00:14:30,010
you will find that ViewModelProviders,

329
00:14:30,010 --> 00:14:32,520
with the S, will appear as a suggestion.

330
00:14:32,520 --> 00:14:34,480
Personally I've got no idea why it was happy

331
00:14:34,480 --> 00:14:37,810
to suggest ViewModelProvider without the S

332
00:14:37,810 --> 00:14:39,460
but not the one we wanted.

333
00:14:39,460 --> 00:14:42,588
After all they both come from Android.arch.lifecycle.

334
00:14:42,588 --> 00:14:44,300
All of this is very new and it's also

335
00:14:44,300 --> 00:14:47,570
in the process of being moved into Android X.

336
00:14:47,570 --> 00:14:49,887
Google are sorting through their support libraries

337
00:14:49,887 --> 00:14:51,350
and there's a blog post about it

338
00:14:51,350 --> 00:14:53,663
that I think is quite interesting to check out.

339
00:14:55,840 --> 00:14:58,355
Life should be a lot simpler after the migration

340
00:14:58,355 --> 00:15:00,300
and we'll no longer have things like

341
00:15:00,300 --> 00:15:02,440
a v7 support library with

342
00:15:02,440 --> 00:15:04,263
a minimum supported Android version.

343
00:15:05,400 --> 00:15:06,760
But that said, I don't recommend that

344
00:15:06,760 --> 00:15:08,690
you switch to these new libraries yet

345
00:15:08,690 --> 00:15:10,055
and you can find more information

346
00:15:10,055 --> 00:15:11,473
about them as you scroll down.

347
00:15:12,800 --> 00:15:15,306
It's talking about the old Android package names

348
00:15:15,306 --> 00:15:17,790
and the new Android package names there.

349
00:15:17,790 --> 00:15:19,060
Again, I don't suggest that you switch

350
00:15:19,060 --> 00:15:20,830
to the new libraries just yet.

351
00:15:20,830 --> 00:15:22,060
If you read through that, you'll find that

352
00:15:22,060 --> 00:15:23,850
this does actually mention the same thing,

353
00:15:23,850 --> 00:15:26,320
to not switch yet from production code.

354
00:15:26,320 --> 00:15:28,050
The next version of Android Studio

355
00:15:28,050 --> 00:15:30,950
will perform the migration of your dependencies

356
00:15:30,950 --> 00:15:33,270
automatically so hopefully Android X

357
00:15:33,270 --> 00:15:35,480
will be out of beta around the time

358
00:15:35,480 --> 00:15:38,430
Android Studio 3.2 is released.

359
00:15:38,430 --> 00:15:39,490
Until then though, stick with

360
00:15:39,490 --> 00:15:41,513
these dependencies that I've shown you.

361
00:15:42,411 --> 00:15:43,290
Alright, so creating an instance

362
00:15:43,290 --> 00:15:45,180
of your view model isn't that easy.

363
00:15:45,180 --> 00:15:48,230
You create, and I'll go back to the code now,

364
00:15:48,230 --> 00:15:50,220
you actually create the static of method

365
00:15:50,220 --> 00:15:52,580
or call the static of method of

366
00:15:52,580 --> 00:15:54,590
the ViewModelProviders class to get

367
00:15:54,590 --> 00:15:56,720
a ViewModelProvider, and then you call

368
00:15:56,720 --> 00:16:00,810
its get method to get the view model type you want.

369
00:16:00,810 --> 00:16:03,740
Here actually what we want is a CalculatorViewModel,

370
00:16:03,740 --> 00:16:08,280
so that's what we specified on line 16 when calling get.

371
00:16:08,280 --> 00:16:09,620
The code to start observing

372
00:16:09,620 --> 00:16:12,230
the view model's LiveData objects is simple.

373
00:16:12,230 --> 00:16:14,503
I'm gonna type that in and then talk about it.

374
00:16:15,402 --> 00:16:19,610
We're going to type viewModel.result.observe

375
00:16:21,660 --> 00:16:24,750
then in parentheses, this comma,

376
00:16:24,750 --> 00:16:28,970
then we want observer, I'm gonna choose this one here.

377
00:16:28,970 --> 00:16:32,980
Specify string, less than and greater than sign

378
00:16:32,980 --> 00:16:35,030
to separate it, and then we want

379
00:16:35,030 --> 00:16:39,978
our left and right curly braces and within there

380
00:16:39,978 --> 00:16:42,790
we're gonna type stringResult

381
00:16:42,790 --> 00:16:46,340
and the arrow, the dash greater than sign,

382
00:16:46,340 --> 00:16:50,390
result.setText and in parentheses

383
00:16:50,390 --> 00:16:51,897
it's gonna be stringResult.

384
00:16:53,095 --> 00:16:54,260
We've got the closing parentheses

385
00:16:54,260 --> 00:16:57,890
closing right curly brace and then closing parentheses.

386
00:16:57,890 --> 00:17:01,175
Right now I need to do a similar thing to newNumber.

387
00:17:01,175 --> 00:17:06,175
viewModel.newNumber.observe,

388
00:17:06,359 --> 00:17:09,079
and we're gonna type this then observer again

389
00:17:11,367 --> 00:17:12,586
and less than greater than,

390
00:17:12,586 --> 00:17:14,063
we're gonna specify string again.

391
00:17:14,970 --> 00:17:17,560
Then we've got our left and right curly braces again

392
00:17:17,560 --> 00:17:18,990
and this time we're gonna type stringNumber

393
00:17:21,740 --> 00:17:25,540
and the arrow which is dash greater than sign,

394
00:17:25,540 --> 00:17:29,940
then newNumber.setText.

395
00:17:29,940 --> 00:17:33,460
In parentheses, it's gonna be stringNumber.

396
00:17:33,460 --> 00:17:35,480
The third line, pretty similar there.

397
00:17:35,480 --> 00:17:40,480
Model., this time it's gonna be operation.observe,

398
00:17:40,560 --> 00:17:44,520
parentheses, this comma, and it's gonna be observer.

399
00:17:44,520 --> 00:17:46,760
Observer again, and again in

400
00:17:46,760 --> 00:17:48,330
the less than and greater than sign

401
00:17:49,737 --> 00:17:51,330
we're gonna put string again

402
00:17:51,330 --> 00:17:52,900
and left and right curly braces.

403
00:17:52,900 --> 00:17:54,850
This time it's gonna be stringOperation

404
00:17:56,040 --> 00:17:58,028
and the dash greater than sign, the arrow,

405
00:17:58,028 --> 00:18:01,390
then we're gonna type operation.text

406
00:18:01,390 --> 00:18:03,507
equals stringOperation.

407
00:18:05,810 --> 00:18:07,460
We set up observer now on each of

408
00:18:07,460 --> 00:18:10,200
the LiveData objects that we're interested in.

409
00:18:10,200 --> 00:18:12,030
The observe function needs an owner,

410
00:18:12,030 --> 00:18:14,170
which will be our activity in this case.

411
00:18:14,170 --> 00:18:16,400
It also needs an observer instance.

412
00:18:16,400 --> 00:18:19,000
Observer is just an interface and you can see there

413
00:18:19,000 --> 00:18:21,450
that we're using landers to provide the callback

414
00:18:21,450 --> 00:18:24,780
that'll be executed when the observed object changes.

415
00:18:24,780 --> 00:18:28,110
If the view model's result LiveData object changes,

416
00:18:28,110 --> 00:18:30,720
our result, which is text, will be set to the new result

417
00:18:30,720 --> 00:18:33,950
and the same thing happens for the other two widgets.

418
00:18:33,950 --> 00:18:36,600
That's the theory, let's see if it actually works.

419
00:18:36,600 --> 00:18:38,100
I'm gonna run the application.

420
00:18:39,400 --> 00:18:40,740
I'll just fast forward this bit

421
00:18:40,740 --> 00:18:43,313
while it's actually starting the emulator.

422
00:18:48,240 --> 00:18:50,123
Okay, we'll just make this a bit bigger.

423
00:18:54,900 --> 00:18:56,330
Alright, so let's do a quick test here.

424
00:18:56,330 --> 00:19:00,173
I'm gonna enter 56 and tap on the modification.

425
00:19:01,270 --> 00:19:03,670
You can see there the display is updated

426
00:19:03,670 --> 00:19:05,900
and we've got the number 56 in the result

427
00:19:05,900 --> 00:19:07,530
and we've also got the modification

428
00:19:07,530 --> 00:19:09,410
as the operation to be performed.

429
00:19:09,410 --> 00:19:13,250
We type seven and equals, you can see

430
00:19:13,250 --> 00:19:14,991
the answer is 392.0.

431
00:19:14,991 --> 00:19:19,090
So far so good, but what about rotating the device?

432
00:19:19,090 --> 00:19:21,250
Let's select division and

433
00:19:21,250 --> 00:19:22,743
I'm gonna rotate the device.

434
00:19:25,060 --> 00:19:27,330
I can see the display there still looks fine,

435
00:19:27,330 --> 00:19:29,560
and if everything's working, 392 should be

436
00:19:29,560 --> 00:19:31,530
divided by the next number.

437
00:19:31,530 --> 00:19:36,530
Let's enter four and equals and you can see that worked.

438
00:19:36,890 --> 00:19:39,380
We got the result 98.0.

439
00:19:39,380 --> 00:19:41,330
We're not saving the state of our app,

440
00:19:41,330 --> 00:19:42,930
the variables for the operation

441
00:19:42,930 --> 00:19:45,130
and the operand, but it still works

442
00:19:45,130 --> 00:19:47,270
after a configuration change.

443
00:19:47,270 --> 00:19:48,760
The view model isn't destroyed

444
00:19:48,760 --> 00:19:52,109
and recreated when the activity is.

445
00:19:52,109 --> 00:19:53,970
When the activity gets recreated,

446
00:19:53,970 --> 00:19:56,390
it subscribes to the view model again

447
00:19:56,390 --> 00:19:58,720
and everything's just as it was

448
00:19:58,720 --> 00:20:00,420
before the activity was destroyed.

449
00:20:01,920 --> 00:20:03,490
That's pretty cool, so I'm gonna finish

450
00:20:03,490 --> 00:20:06,180
the video now just by reviewing our code.

451
00:20:06,180 --> 00:20:08,420
Firstly, looking back at MainActivity.

452
00:20:08,420 --> 00:20:10,210
I think you'd agree that's significantly

453
00:20:10,210 --> 00:20:12,850
easier now, really quite simple.

454
00:20:12,850 --> 00:20:14,790
It really doesn't do anything now

455
00:20:14,790 --> 00:20:17,610
that isn't directly related to the UI.

456
00:20:17,610 --> 00:20:18,921
It's really just setting up,

457
00:20:18,921 --> 00:20:21,950
after the layout is inflated on line 15

458
00:20:23,200 --> 00:20:24,980
there's a call there to the getContentView

459
00:20:24,980 --> 00:20:26,383
on the start of onCreate.

460
00:20:27,636 --> 00:20:28,490
The next bit of code there observes

461
00:20:28,490 --> 00:20:30,530
the LiveData objects and updates

462
00:20:30,530 --> 00:20:32,680
the various widgets when they change.

463
00:20:32,680 --> 00:20:33,990
Everything really there is just

464
00:20:33,990 --> 00:20:36,070
setting up for the listeners.

465
00:20:36,070 --> 00:20:37,250
The listeners don't attempt to do

466
00:20:37,250 --> 00:20:38,940
any processing here, they're just

467
00:20:38,940 --> 00:20:41,540
calling functions in the view model

468
00:20:41,540 --> 00:20:44,170
and the view model actually does all the work.

469
00:20:44,170 --> 00:20:45,550
What we've done is we've separated

470
00:20:45,550 --> 00:20:48,240
the display from the app's logic

471
00:20:48,240 --> 00:20:50,040
and the activity's only concerned with

472
00:20:50,040 --> 00:20:54,020
displaying the data and responding to user interaction.

473
00:20:54,020 --> 00:20:56,050
In the CalculatorViewModel class,

474
00:20:56,050 --> 00:20:58,800
we've got all the code that deals with the app's logic.

475
00:20:59,990 --> 00:21:01,800
This is still a very simple app

476
00:21:01,800 --> 00:21:03,190
and we'll be seeing view models

477
00:21:03,190 --> 00:21:05,040
that do a bit more later.

478
00:21:05,040 --> 00:21:06,900
Notice that the CalculatorViewModel class

479
00:21:06,900 --> 00:21:09,210
doesn't have any knowledge about its activity.

480
00:21:09,210 --> 00:21:10,210
In fact, it doesn't even know

481
00:21:10,210 --> 00:21:11,680
that there is an activity.

482
00:21:11,680 --> 00:21:13,180
We could use it from a fragment

483
00:21:13,180 --> 00:21:16,250
or a service and it would still work.

484
00:21:16,250 --> 00:21:18,880
What it does do is expose LiveData objects

485
00:21:18,880 --> 00:21:21,360
for the results it needs to pass back

486
00:21:21,360 --> 00:21:22,490
and doesn't have to worry about

487
00:21:22,490 --> 00:21:24,998
whether there's something observing them or not.

488
00:21:24,998 --> 00:21:26,860
LiveData takes care of unsubscribing

489
00:21:26,860 --> 00:21:29,750
any observers if they're no longer active.

490
00:21:29,750 --> 00:21:31,610
When they subscribe again, they get

491
00:21:31,610 --> 00:21:35,100
the latest values from the LiveData objects.

492
00:21:35,100 --> 00:21:36,370
Alright, so I'm gonna stop the video here

493
00:21:36,370 --> 00:21:38,450
because this turned into a marathon one.

494
00:21:38,450 --> 00:21:39,870
In the next video, we're gonna make

495
00:21:39,870 --> 00:21:41,748
a slight change to the view model

496
00:21:41,748 --> 00:21:45,760
so that it doesn't expose MutableLiveData objects.

497
00:21:45,760 --> 00:21:47,060
See you in the next video.

