1
00:00:00,000 --> 00:00:02,500
(light music)

2
00:00:05,220 --> 00:00:06,930
We've separated the logic of our app

3
00:00:06,930 --> 00:00:08,520
from the user interface, the UI,

4
00:00:08,520 --> 00:00:11,190
and our activity doesn't do anything

5
00:00:11,190 --> 00:00:15,040
that isn't directly related to interacting with the user.

6
00:00:15,040 --> 00:00:17,780
But I did mention that we shouldn't really be exposing

7
00:00:17,780 --> 00:00:20,880
mutable live data objects because there's a risk

8
00:00:20,880 --> 00:00:23,810
that the view model's owner could change them.

9
00:00:23,810 --> 00:00:26,230
So in this video we're going to look at how to fix that.

10
00:00:26,230 --> 00:00:29,260
If we don't want to expose the mutable live data object

11
00:00:29,260 --> 00:00:31,770
then the first step is to mark them private

12
00:00:31,770 --> 00:00:33,430
in Calculator View Model.

13
00:00:33,430 --> 00:00:36,220
Now class, to do that we're going to do just that.

14
00:00:36,220 --> 00:00:39,720
On line 16, private,

15
00:00:39,720 --> 00:00:41,980
and we'll do the same for line 17 and 18

16
00:00:43,490 --> 00:00:45,790
marking all three as private.

17
00:00:45,790 --> 00:00:49,120
Once we've done that, we go back to main activity.

18
00:00:49,120 --> 00:00:52,360
You can see now that in fact we break main activity

19
00:00:52,360 --> 00:00:55,090
because it can't access the private attributes

20
00:00:55,090 --> 00:00:56,260
of the view model.

21
00:00:56,260 --> 00:00:57,100
What we're going to do though

22
00:00:57,100 --> 00:00:59,940
is create new attributes that it can use.

23
00:00:59,940 --> 00:01:02,700
So I'm gonna modify main activity to use these,

24
00:01:02,700 --> 00:01:05,470
even though they haven't been created just yet.

25
00:01:05,470 --> 00:01:06,450
So we'll be getting an error,

26
00:01:06,450 --> 00:01:09,780
but what we'll do, instead of getting our result

27
00:01:09,780 --> 00:01:13,560
It's gonna be string result,

28
00:01:13,560 --> 00:01:14,910
instead of new number.

29
00:01:14,910 --> 00:01:17,980
It's gonna be string new number.

30
00:01:17,980 --> 00:01:21,520
Noticing I'm changing the capitalization there of the words,

31
00:01:21,520 --> 00:01:23,683
and then string operation,

32
00:01:24,530 --> 00:01:26,030
instead of operation.

33
00:01:26,030 --> 00:01:27,410
And again, we've got errors,

34
00:01:27,410 --> 00:01:29,640
but they'll go once we create the attributes

35
00:01:29,640 --> 00:01:31,890
back in Calculator View Model.

36
00:01:31,890 --> 00:01:34,480
We'll go and start looking at that now.

37
00:01:34,480 --> 00:01:37,220
So for each of our mutable live data objects,

38
00:01:37,220 --> 00:01:39,013
we need corresponding live data object

39
00:01:39,013 --> 00:01:41,700
that the observer can use.

40
00:01:41,700 --> 00:01:44,623
I'm gonna leave result to last, do that other two first.

41
00:01:45,660 --> 00:01:49,000
So I'm gonna start, just making this space with new number,

42
00:01:49,000 --> 00:01:51,360
set below the definition for new number,

43
00:01:51,360 --> 00:01:53,857
we're going to type val stringNewNumber.

44
00:01:56,205 --> 00:01:59,673
It's gonna colon, LiveData, instead of mutablelivedata.

45
00:01:59,673 --> 00:02:02,490
Then, we can define that its a string, so left and right,

46
00:02:02,490 --> 00:02:04,970
less than and greater than signs at the string there,

47
00:02:04,970 --> 00:02:07,140
we're gonna accept that if an employer asks you to do that,

48
00:02:07,140 --> 00:02:08,673
you can accept that,

49
00:02:09,917 --> 00:02:11,797
and then on the next line,

50
00:02:11,797 --> 00:02:15,350
we'll do a tab, and type get, in parentheses,

51
00:02:15,350 --> 00:02:17,113
equals new number.

52
00:02:18,250 --> 00:02:19,400
That's our first definition,

53
00:02:19,400 --> 00:02:21,533
and let's do the same now for operation.

54
00:02:23,140 --> 00:02:24,720
So below the definition of operation,

55
00:02:24,720 --> 00:02:27,600
val string operation,

56
00:02:27,600 --> 00:02:30,203
colon, live data,

57
00:02:30,203 --> 00:02:31,250
and less than, greater than sign,

58
00:02:31,250 --> 00:02:35,050
and I'm going to put String, then parentheses on the end.

59
00:02:35,050 --> 00:02:38,560
Then on the next line, get, parentheses,

60
00:02:38,560 --> 00:02:40,520
equals operation.

61
00:02:40,520 --> 00:02:41,980
And of course, it shouldn't have been parentheses

62
00:02:41,980 --> 00:02:44,350
on the end of the string operation line.

63
00:02:44,350 --> 00:02:46,980
Alright, so at the moment, we've added two public fields,

64
00:02:46,980 --> 00:02:49,940
with a gather that thus returns the corresponding

65
00:02:49,940 --> 00:02:52,290
mutable live data objects,

66
00:02:52,290 --> 00:02:55,120
because the top of these fields is live data,

67
00:02:55,120 --> 00:02:57,680
the owner won't be able to use the value

68
00:02:57,680 --> 00:02:59,720
and post value attributes.

69
00:02:59,720 --> 00:03:01,930
The owner will see live data objects,

70
00:03:01,930 --> 00:03:03,960
not mutable live data objects.

71
00:03:03,960 --> 00:03:06,890
And again, live data objects don't have the value

72
00:03:06,890 --> 00:03:09,280
of post value attributes.

73
00:03:09,280 --> 00:03:12,140
Mutable live data is a subclass of live data,

74
00:03:12,140 --> 00:03:14,010
which how we're able to do this.

75
00:03:14,010 --> 00:03:16,580
Right, so we go back to MainActivity, check that out.

76
00:03:16,580 --> 00:03:19,720
We can see now that two of the errors have been fixed,

77
00:03:19,720 --> 00:03:21,920
and I've left result to last,

78
00:03:21,920 --> 00:03:24,700
because we're gonna be doing that one slightly differently.

79
00:03:24,700 --> 00:03:28,020
So we go back to our Calculator View Model,

80
00:03:28,020 --> 00:03:29,230
and specifically down here

81
00:03:29,230 --> 00:03:32,570
to the perform operation function.

82
00:03:32,570 --> 00:03:37,160
Notice that it's using toString function on line 85

83
00:03:37,160 --> 00:03:39,060
to convert operand1 to a string

84
00:03:39,060 --> 00:03:41,350
before storing it in result.

85
00:03:41,350 --> 00:03:43,690
Now, it would be more convenient to stick with a double

86
00:03:43,690 --> 00:03:46,207
inside the view model when we're dealing with the operand

87
00:03:46,207 --> 00:03:47,660
and the result.

88
00:03:47,660 --> 00:03:51,610
So what I'm going to do is remove the toString call first.

89
00:03:51,610 --> 00:03:54,660
Delete that out, and that's gonna cause an error of course,

90
00:03:54,660 --> 00:03:56,490
but we'll fix that next.

91
00:03:56,490 --> 00:03:58,000
I'm surprised that we've got an error there,

92
00:03:58,000 --> 00:04:00,150
cause that's expecting a string.

93
00:04:00,150 --> 00:04:03,570
The error's because result is a lot of data holding a string

94
00:04:03,570 --> 00:04:05,410
and we're assigning a double to it.

95
00:04:05,410 --> 00:04:07,860
We can fix that by changing the declaration of result

96
00:04:07,860 --> 00:04:09,590
on top of the class.

97
00:04:09,590 --> 00:04:11,378
Let's go back and do that.

98
00:04:11,378 --> 00:04:13,939
So we change result from a string here

99
00:04:13,939 --> 00:04:15,113
to a double.

100
00:04:17,720 --> 00:04:20,779
You can see then that typing it down perform operation,

101
00:04:20,779 --> 00:04:22,500
the error's cleared, and we've got a green tick

102
00:04:22,500 --> 00:04:24,300
on the top right hand corner of the screen.

103
00:04:24,300 --> 00:04:26,520
Indicating that everything's okay.

104
00:04:26,520 --> 00:04:28,540
The problem we now got though is that result

105
00:04:28,540 --> 00:04:31,910
solves a double, but we want to send a string to the owner.

106
00:04:31,910 --> 00:04:35,230
Now, this is extremely common; your mutable live data

107
00:04:35,230 --> 00:04:38,480
stores objects of one type, but the owner really needs

108
00:04:38,480 --> 00:04:40,780
to be observing a different type.

109
00:04:40,780 --> 00:04:43,710
In fact, it's so common that the last cycle components

110
00:04:43,710 --> 00:04:45,820
have a transformations class

111
00:04:45,820 --> 00:04:47,840
to deal with situations like this.

112
00:04:47,840 --> 00:04:49,833
So what we're gonna do is add the public attribute first,

113
00:04:49,833 --> 00:04:52,320
then we'll look at how to change its type.

114
00:04:52,320 --> 00:04:53,920
I'm gonna put this under result,

115
00:04:53,920 --> 00:04:55,590
the result definition.

116
00:04:55,590 --> 00:04:57,873
Val, stringResult.

117
00:04:57,873 --> 00:05:00,698
Colon, live data,

118
00:05:00,698 --> 00:05:02,260
and less than and greater than signs again.

119
00:05:02,260 --> 00:05:03,093
String,

120
00:05:05,170 --> 00:05:08,773
and on the next line, get, parentheses, equals result.

121
00:05:10,440 --> 00:05:13,240
Now, we've got an error, if we hover over that, we can see.

122
00:05:13,240 --> 00:05:14,420
Because we're attempting at the moment

123
00:05:14,420 --> 00:05:17,500
to assign a live data double to a variable that we have to

124
00:05:17,500 --> 00:05:20,720
clear as live data string.

125
00:05:20,720 --> 00:05:23,760
What we need is somewhere to transform the double live data

126
00:05:23,760 --> 00:05:25,360
into a string one,

127
00:05:25,360 --> 00:05:27,247
and that's where this transformations class

128
00:05:27,247 --> 00:05:29,690
that I'm about to show you comes into play.

129
00:05:29,690 --> 00:05:32,840
So, instead of putting get, parentheses, equals result,

130
00:05:32,840 --> 00:05:34,670
we're gonna put get, parentheses, equals,

131
00:05:34,670 --> 00:05:37,350
and it's gonna be transformations, capital t,

132
00:05:37,350 --> 00:05:41,620
Transformations, dot map, and then parentheses,

133
00:05:41,620 --> 00:05:45,540
we're gonna add result as the first argument, comma,

134
00:05:45,540 --> 00:05:48,670
and we're gonna add left and right curly braces.

135
00:05:48,670 --> 00:05:50,190
Then within those left and right curly braces

136
00:05:50,190 --> 00:05:54,350
we're gonna type it dot, toString, parentheses,

137
00:05:54,350 --> 00:05:56,070
and outside of the right curly brace,

138
00:05:56,070 --> 00:05:58,563
we're gonna add a closing, right parentheses.

139
00:05:59,399 --> 00:06:02,010
Right, and if we click on map, we'll then check that out,

140
00:06:02,010 --> 00:06:03,380
see what it does.

141
00:06:03,380 --> 00:06:06,500
You can see that it applies a function to each value

142
00:06:06,500 --> 00:06:08,720
emitted by the source live data,

143
00:06:08,720 --> 00:06:10,570
so that's result in our case,

144
00:06:10,570 --> 00:06:13,550
and then the result then returns into live data

145
00:06:13,550 --> 00:06:16,570
that emits the modified values.

146
00:06:16,570 --> 00:06:17,700
I'm closing that down again.

147
00:06:17,700 --> 00:06:20,840
Our function's really simple, it's just the lambda

148
00:06:20,840 --> 00:06:23,830
that returns to toString value of the double.

149
00:06:23,830 --> 00:06:26,120
So we'll now move the call toString

150
00:06:26,120 --> 00:06:28,210
from the perform operation function

151
00:06:28,210 --> 00:06:29,860
to the point where it's needed,

152
00:06:29,860 --> 00:06:31,690
providing a string to the owner.

153
00:06:31,690 --> 00:06:34,410
So this allows the view model to work with types

154
00:06:34,410 --> 00:06:37,140
that are most convenient and only convert them

155
00:06:37,140 --> 00:06:40,370
at the final stage where they're going to be observed.

156
00:06:40,370 --> 00:06:43,093
We didn't do that with the new number object,

157
00:06:44,000 --> 00:06:46,660
making it a double in other words, because we're receiving

158
00:06:46,660 --> 00:06:49,880
characters in digitPressed in that function.

159
00:06:49,880 --> 00:06:52,590
It's therefore much easier to build up new number

160
00:06:52,590 --> 00:06:54,920
by appending the next digital string,

161
00:06:54,920 --> 00:06:56,820
and it's a result I think is more convenient

162
00:06:56,820 --> 00:06:59,010
to keep new number as a string.

163
00:06:59,010 --> 00:07:01,530
You may however decide to code this differently,

164
00:07:01,530 --> 00:07:03,940
and have the activity use a single function.

165
00:07:03,940 --> 00:07:06,100
It could have for example passed both the number

166
00:07:06,100 --> 00:07:08,280
from its inner text, and the operation

167
00:07:08,280 --> 00:07:09,870
in a single function call.

168
00:07:09,870 --> 00:07:12,640
So, in that case, the digital buttons wouldn't call

169
00:07:12,640 --> 00:07:14,720
a function in the live data class.

170
00:07:14,720 --> 00:07:18,200
That just put the characters into the inner text wigeon.

171
00:07:18,200 --> 00:07:20,130
Typing one of the operator buttons will then call

172
00:07:20,130 --> 00:07:22,650
a live data function, then pass in the number

173
00:07:22,650 --> 00:07:25,200
from the inner text wigeon in the operation.

174
00:07:25,200 --> 00:07:27,850
Main activity would still only be concerned with UI,

175
00:07:27,850 --> 00:07:29,000
so that's fine.

176
00:07:29,000 --> 00:07:31,960
There's often many ways to organise the code,

177
00:07:31,960 --> 00:07:32,793
I wanted to show you

178
00:07:32,793 --> 00:07:35,840
how to observe simple live data objects at once,

179
00:07:35,840 --> 00:07:38,360
but that doesn't mean that you have to do it that way.

180
00:07:38,360 --> 00:07:40,650
If you wanna see what the alternative implementations

181
00:07:40,650 --> 00:07:43,770
might look like, I've added calculator two

182
00:07:43,770 --> 00:07:45,570
to the resources for this video.

183
00:07:45,570 --> 00:07:47,397
Or, have a go yourself first,

184
00:07:47,397 --> 00:07:49,810
and then compare your result to mine.

185
00:07:49,810 --> 00:07:51,420
And just before I finish the video, there is still

186
00:07:51,420 --> 00:07:54,830
one minor change that we can make here.

187
00:07:54,830 --> 00:07:57,050
You can see that we've got warnings over here,

188
00:07:57,050 --> 00:08:00,450
and have a look on line 20, we can see that it's

189
00:08:00,450 --> 00:08:01,890
underlined in grey.

190
00:08:01,890 --> 00:08:04,100
And when we move our mouse, there you can see it set up,

191
00:08:04,100 --> 00:08:07,160
android studio is was suggesting that the lambda argument

192
00:08:07,160 --> 00:08:09,490
should be moved out of parentheses.

193
00:08:09,490 --> 00:08:12,230
So click into there, we come over here

194
00:08:12,230 --> 00:08:13,710
and click on the light bulb,

195
00:08:13,710 --> 00:08:16,210
and take android studio's suggestion to move

196
00:08:16,210 --> 00:08:18,373
the lambda argument out of parentheses.

197
00:08:19,380 --> 00:08:21,163
That there clears the warning, and you can see now

198
00:08:21,163 --> 00:08:24,190
that we've got in the top right hand corner,

199
00:08:24,190 --> 00:08:25,890
we've got a green tick,

200
00:08:25,890 --> 00:08:27,480
so we're good to go.

201
00:08:27,480 --> 00:08:29,440
So I'll stop the video here now.

202
00:08:29,440 --> 00:08:31,410
In the next one, we're gonna see another advantage

203
00:08:31,410 --> 00:08:35,140
of completely separating the UI from the program's logic.

204
00:08:35,140 --> 00:08:36,440
See you in the next video.

