1
00:00:00,201 --> 00:00:01,636
(bright music)

2
00:00:01,636 --> 00:00:02,562
(swooshing)

3
00:00:02,562 --> 00:00:04,451
(keyboard clicking)

4
00:00:04,451 --> 00:00:06,660
Alright, so I mentioned at the end

5
00:00:06,660 --> 00:00:08,810
of the last video that we've got a much more

6
00:00:08,810 --> 00:00:10,952
efficient implementation of of the get view method.

7
00:00:10,952 --> 00:00:13,699
But we can improve it a lot further.

8
00:00:13,699 --> 00:00:15,288
And what we're going to do is we're to

9
00:00:15,288 --> 00:00:17,690
employ something called the view holder

10
00:00:17,690 --> 00:00:19,108
pattern to do that.

11
00:00:19,108 --> 00:00:21,950
Now looking at this get view code

12
00:00:21,950 --> 00:00:24,750
you can see we're using find view by ID

13
00:00:24,750 --> 00:00:26,950
to get a reference to each of the widgets

14
00:00:26,950 --> 00:00:27,783
in the view

15
00:00:27,783 --> 00:00:29,400
and we're doing that every time.

16
00:00:29,400 --> 00:00:30,958
Now even when we're reusing a few

17
00:00:30,958 --> 00:00:33,814
we still have to find the individual text widgets

18
00:00:33,814 --> 00:00:35,768
in order to change their text.

19
00:00:35,768 --> 00:00:39,710
Now find view by ID is a really costly operation.

20
00:00:39,710 --> 00:00:41,516
It takes a while to go through the view,

21
00:00:41,516 --> 00:00:44,020
searching for the correct widget.

22
00:00:44,020 --> 00:00:46,292
Now it is necessary to do that a lot of the time

23
00:00:46,292 --> 00:00:49,770
but here we're reusing views, aren't we?

24
00:00:49,770 --> 00:00:52,380
Which means we're calling find view by ID

25
00:00:52,380 --> 00:00:54,950
to find the widgets in a view

26
00:00:54,950 --> 00:00:56,453
that we've already searched last time

27
00:00:56,453 --> 00:00:58,000
that we used it.

28
00:00:58,000 --> 00:00:59,930
Now the widgets haven't changed since last time

29
00:00:59,930 --> 00:01:02,594
so it makes since to store those references somewhere

30
00:01:02,594 --> 00:01:06,500
and use it to store references to the text view widgets

31
00:01:06,500 --> 00:01:08,930
rather than searching for them every time.

32
00:01:08,930 --> 00:01:11,850
So that's what the view holder pattern does.

33
00:01:11,850 --> 00:01:13,280
And it's called the view holder pattern

34
00:01:13,280 --> 00:01:15,804
because it uses a smaller class to hold the views

35
00:01:15,804 --> 00:01:18,120
that we found the last time.

36
00:01:18,120 --> 00:01:20,020
So we're going to create a class that

37
00:01:20,020 --> 00:01:21,831
has a field for each of the widgets

38
00:01:21,831 --> 00:01:23,930
that we need to find.

39
00:01:23,930 --> 00:01:25,880
Now the only other thing that we need is

40
00:01:25,880 --> 00:01:29,190
some way to store the instances of this class

41
00:01:29,190 --> 00:01:31,600
and view objects have a tag field that

42
00:01:31,600 --> 00:01:33,565
can be used for that purpose.

43
00:01:33,565 --> 00:01:34,767
So I'm going to type in the code

44
00:01:34,767 --> 00:01:36,820
and then explain what it's doing.

45
00:01:36,820 --> 00:01:40,080
But first we want to create a class called view holder.

46
00:01:40,080 --> 00:01:41,200
Now this can be called anything but

47
00:01:41,200 --> 00:01:43,020
the usual name is view holder.

48
00:01:43,020 --> 00:01:44,240
Now because it's such a small class,

49
00:01:44,240 --> 00:01:45,670
I'm going to put it at the start of the file.

50
00:01:45,670 --> 00:01:48,652
So I'm going to open up our project again,

51
00:01:48,652 --> 00:01:53,260
go into feed adaptor, well it's actually there anyway,

52
00:01:53,260 --> 00:01:54,320
but I can go to the top there

53
00:01:54,320 --> 00:01:57,310
and we're going to put it above the feed adaptor

54
00:01:57,310 --> 00:01:58,143
class definition,

55
00:01:58,143 --> 00:02:00,243
so I'll put it above that.

56
00:02:01,581 --> 00:02:06,400
So it's going to be class view holder,

57
00:02:06,400 --> 00:02:08,839
and notice when I start typing there

58
00:02:08,839 --> 00:02:13,430
that the icon for feed adaptor in the project pane,

59
00:02:13,430 --> 00:02:16,020
so it's a cut and class icon CK basically, so.

60
00:02:16,020 --> 00:02:18,053
Now, class, view holder,

61
00:02:19,626 --> 00:02:24,361
parenthesis V colon view, parenthesis

62
00:02:24,361 --> 00:02:25,746
and we'll go through

63
00:02:25,746 --> 00:02:27,820
and we'll add our curly braces.

64
00:02:27,820 --> 00:02:32,470
We're going to type val, TV name, colon,

65
00:02:32,470 --> 00:02:36,793
text view equals v.FindViewByID,

66
00:02:38,080 --> 00:02:39,833
R.ID.TVname

67
00:02:42,832 --> 00:02:46,430
next one, val, TV artist, colon,

68
00:02:46,430 --> 00:02:48,180
it's also text view as you'll note,

69
00:02:49,122 --> 00:02:51,413
and that's equal to V.FindViewByID,

70
00:02:52,750 --> 00:02:54,380
R.ID.TVartist

71
00:02:56,314 --> 00:03:00,117
and the last one is val, TV summary, colon,

72
00:03:03,123 --> 00:03:08,123
text view equals V.FindViewByID,

73
00:03:10,660 --> 00:03:11,790
R.ID.TVsummary

74
00:03:11,790 --> 00:03:13,582
The other thing I would do is I'm going

75
00:03:13,582 --> 00:03:14,415
to leave two lines

76
00:03:14,415 --> 00:03:16,393
so two big lines between the classes.

77
00:03:17,666 --> 00:03:19,850
Now that's actually a Python convention

78
00:03:19,850 --> 00:03:22,170
but I think it does help to separate them

79
00:03:22,170 --> 00:03:23,600
so it's now my convention that I'm using

80
00:03:23,600 --> 00:03:27,351
for Kotlin until someone publishes a Kotlin style guide.

81
00:03:27,351 --> 00:03:30,320
Alright so the view holder class is very basic.

82
00:03:30,320 --> 00:03:33,190
It just uses find view by ID to find the widgets

83
00:03:33,190 --> 00:03:35,080
in the view V

84
00:03:35,080 --> 00:03:36,990
and stores them in its fields.

85
00:03:36,990 --> 00:03:38,510
Now I'm doing this slightly different

86
00:03:38,510 --> 00:03:40,440
to examples you find out there

87
00:03:40,440 --> 00:03:42,230
so let's say what Google has to say about

88
00:03:42,230 --> 00:03:43,770
the view holder pattern.

89
00:03:43,770 --> 00:03:45,420
I'm going to just open a browser.

90
00:03:49,396 --> 00:03:50,793
So paste that in.

91
00:03:53,861 --> 00:03:57,200
Now the current examples are in Java

92
00:03:57,200 --> 00:04:00,030
but we can see that the view holder is just a

93
00:04:00,030 --> 00:04:01,810
basic class holding their references to the

94
00:04:01,810 --> 00:04:03,740
fields that we want to update.

95
00:04:03,740 --> 00:04:05,817
Now the first paragraph explains the reasons for it.

96
00:04:05,817 --> 00:04:09,320
Coding point of view by ID frequently can

97
00:04:09,320 --> 00:04:10,390
slow down performance.

98
00:04:10,390 --> 00:04:12,020
You can see that over here.

99
00:04:12,020 --> 00:04:14,950
Now Google's example puts the code to find view by ID

100
00:04:14,950 --> 00:04:16,829
in the get view method.

101
00:04:16,829 --> 00:04:19,750
Whereas I've always put them in the view holder class.

102
00:04:19,750 --> 00:04:21,260
Now in Java I don't think it made any

103
00:04:21,260 --> 00:04:22,540
difference either way

104
00:04:22,540 --> 00:04:25,710
but in Kotlin the situation's slightly different.

105
00:04:25,710 --> 00:04:27,462
So looking at the Java code that calls

106
00:04:27,462 --> 00:04:30,103
find view by ID for each of the widgets,

107
00:04:32,070 --> 00:04:33,490
scroll down there,

108
00:04:33,490 --> 00:04:37,470
they're all initialised to null in the view holder class.

109
00:04:37,470 --> 00:04:39,137
So if you want to do it that was in Kotlin

110
00:04:39,137 --> 00:04:41,580
you're going to have to use the nullable text views

111
00:04:41,580 --> 00:04:43,640
taught for our text views.

112
00:04:43,640 --> 00:04:45,551
Now the way I'm suggesting avoids that.

113
00:04:45,551 --> 00:04:48,170
The properties are initialised at the time

114
00:04:48,170 --> 00:04:49,400
they're created

115
00:04:49,400 --> 00:04:52,530
and we can use the num null text view type.

116
00:04:52,530 --> 00:04:54,550
Now we don't like nullable types in Kotlin

117
00:04:54,550 --> 00:04:56,950
so I'm sticking with this way of doing it.

118
00:04:56,950 --> 00:04:58,350
Alright so back to the code,

119
00:04:59,540 --> 00:05:01,110
and I'm just going to close that for now

120
00:05:01,110 --> 00:05:02,530
and we'll update that later 'cause I've shown

121
00:05:02,530 --> 00:05:04,660
you how to do that in a previous video,

122
00:05:04,660 --> 00:05:06,650
alright so I'm going to change the get view method

123
00:05:06,650 --> 00:05:07,833
to use the view holder,

124
00:05:07,833 --> 00:05:09,500
then go through how it all works.

125
00:05:09,500 --> 00:05:12,521
So we're going to go down to the get view method.

126
00:05:12,521 --> 00:05:15,717
We're going to start by deleting these three lines.

127
00:05:15,717 --> 00:05:17,923
Well actually these three lines up here.

128
00:05:19,396 --> 00:05:20,750
And we're deleting them

129
00:05:20,750 --> 00:05:21,780
because we don't need them any more.

130
00:05:21,780 --> 00:05:23,190
Well actually what I'll do is I'll just comment

131
00:05:23,190 --> 00:05:24,240
them out for now.

132
00:05:24,240 --> 00:05:26,150
But we don't need them any more with this approach

133
00:05:26,150 --> 00:05:27,310
we're about to take.

134
00:05:27,310 --> 00:05:30,797
So what we want to do is create a new view holder object

135
00:05:30,797 --> 00:05:33,970
if we're having to create a new view.

136
00:05:33,970 --> 00:05:35,810
So we've got this code here up above

137
00:05:35,810 --> 00:05:38,073
if convert view equals null.

138
00:05:38,073 --> 00:05:39,520
And we've got the log here get view called with

139
00:05:39,520 --> 00:05:40,353
null convert view.

140
00:05:40,353 --> 00:05:43,020
That's where we're creating a new view.

141
00:05:43,020 --> 00:05:44,180
So what we're going to do is we can put

142
00:05:44,180 --> 00:05:45,580
view equals inflate,

143
00:05:45,580 --> 00:05:48,270
inflate.inflate that's still correct.

144
00:05:48,270 --> 00:05:49,430
What we're going to do after that is

145
00:05:49,430 --> 00:05:54,430
we're going to top view holder equals view holder

146
00:05:55,713 --> 00:05:57,230
parenthesis view

147
00:05:58,220 --> 00:06:02,787
and we're going to do view.tag equals view holder.

148
00:06:04,700 --> 00:06:06,410
And we'll clear up that area in a minute.

149
00:06:06,410 --> 00:06:09,630
Now otherwise if it'd been past the view to reuse

150
00:06:09,630 --> 00:06:11,080
then we're going to retrieve the view holder

151
00:06:11,080 --> 00:06:12,630
from this tag with the else.

152
00:06:12,630 --> 00:06:15,230
So we've got the view equals convert view

153
00:06:15,230 --> 00:06:16,160
which is still correct

154
00:06:16,160 --> 00:06:20,199
but then we've got to do view holder equals

155
00:06:20,199 --> 00:06:24,683
view.tag as view holder.

156
00:06:27,030 --> 00:06:29,790
Okay, alright so we've got this error

157
00:06:29,790 --> 00:06:32,780
and that's because we need to declare our view holder.

158
00:06:32,780 --> 00:06:34,065
So let's actually do that.

159
00:06:34,065 --> 00:06:35,570
That's going to be at the start of the method

160
00:06:35,570 --> 00:06:36,403
under the val view.

161
00:06:36,403 --> 00:06:41,360
So we're going to put val view holder colon view holder

162
00:06:45,299 --> 00:06:48,410
and that clears up most of those errors.

163
00:06:48,410 --> 00:06:50,750
So all that's left now is to put the text

164
00:06:50,750 --> 00:06:53,300
into the view holder's properties instead of

165
00:06:53,300 --> 00:06:55,520
using the variables that we've deleted.

166
00:06:55,520 --> 00:06:57,300
So let's go ahead and modify those lines.

167
00:06:57,300 --> 00:07:00,410
The code down lines 60 through 62.

168
00:07:00,410 --> 00:07:02,440
Bearing in mind that 62 was commented out

169
00:07:02,440 --> 00:07:05,630
when we were testing in the previous video

170
00:07:05,630 --> 00:07:06,840
so we're going to un-comment that.

171
00:07:06,840 --> 00:07:08,220
We're going to change this though

172
00:07:08,220 --> 00:07:12,150
instead of TVname.text equals current app.name

173
00:07:12,150 --> 00:07:15,150
we're going to use the view holder instead.

174
00:07:15,150 --> 00:07:17,461
So we'll put view holder,

175
00:07:17,461 --> 00:07:20,390
dot in front of that,

176
00:07:21,817 --> 00:07:23,417
and do that for all three lines.

177
00:07:24,774 --> 00:07:27,330
Alright so what have we basically done here now?

178
00:07:27,330 --> 00:07:29,280
Well if convert view is null,

179
00:07:29,280 --> 00:07:31,240
we're doing that test on line 40,

180
00:07:31,240 --> 00:07:33,380
we inflate a new view as before.

181
00:07:33,380 --> 00:07:35,440
And also what we're doing then is creating

182
00:07:35,440 --> 00:07:36,700
a new view holder object

183
00:07:36,700 --> 00:07:38,940
and storing it in the view's tag

184
00:07:38,940 --> 00:07:40,513
using the set tag method.

185
00:07:41,790 --> 00:07:43,230
Well essentially that's what we're doing anyway

186
00:07:43,230 --> 00:07:45,623
with the view.tag equals view holder.

187
00:07:46,520 --> 00:07:48,170
Now if we have been given back an

188
00:07:49,163 --> 00:07:49,996
existing view by the list view

189
00:07:49,996 --> 00:07:51,630
then we're retrieving view holder from its

190
00:07:51,630 --> 00:07:53,387
tag using the get tag method.

191
00:07:53,387 --> 00:07:54,780
And in this case we're just accessing

192
00:07:54,780 --> 00:07:56,570
the property view.tag

193
00:07:56,570 --> 00:07:58,003
as view holder we're assigning that or

194
00:07:58,003 --> 00:08:01,291
replacing that into our view holder variable.

195
00:08:01,291 --> 00:08:03,437
Now the tag is an object so

196
00:08:03,437 --> 00:08:06,220
we've got to cast it to a view holder

197
00:08:06,220 --> 00:08:07,590
but we know it will be a view holder

198
00:08:07,590 --> 00:08:08,950
because we put it there.

199
00:08:08,950 --> 00:08:11,457
Now the Android framework doesn't use that tag field

200
00:08:11,457 --> 00:08:14,270
so we can be sure that whatever we store in it

201
00:08:14,270 --> 00:08:16,060
won't be touched by Android.

202
00:08:16,060 --> 00:08:17,690
That's this as view holder when we're

203
00:08:17,690 --> 00:08:18,615
actually casting it.

204
00:08:18,615 --> 00:08:21,230
And within retrieving the application record

205
00:08:21,230 --> 00:08:22,880
from the list as before

206
00:08:22,880 --> 00:08:25,000
and setting it's values to the widgets that are stored

207
00:08:25,000 --> 00:08:25,963
in the view holder.

208
00:08:26,987 --> 00:08:29,632
And obviously we're doing that on lines 58 through 60.

209
00:08:29,632 --> 00:08:33,409
So find view by ID is now called when a new

210
00:08:33,409 --> 00:08:35,650
view has to be inflated otherwise

211
00:08:35,650 --> 00:08:37,080
the widgets have already been found

212
00:08:37,080 --> 00:08:40,602
and references to them are stored in the view holder.

213
00:08:41,549 --> 00:08:42,450
Now when I run this app,

214
00:08:42,450 --> 00:08:44,250
which I'm going to do now,

215
00:08:44,250 --> 00:08:46,210
you probably won't notice much in the way

216
00:08:46,210 --> 00:08:47,173
of performance.

217
00:08:48,180 --> 00:08:50,410
In other words, much important improvement

218
00:08:50,410 --> 00:08:51,420
in the speed

219
00:08:51,420 --> 00:08:53,160
and that's because the new emulators are

220
00:08:53,160 --> 00:08:55,173
actually very fast once they're started up.

221
00:08:55,173 --> 00:08:57,376
Yeah you may not notice any speed improvements

222
00:08:57,376 --> 00:09:00,095
on a modern Android device with this app either.

223
00:09:00,095 --> 00:09:02,500
But when you come to add animations in

224
00:09:02,500 --> 00:09:03,650
list views though

225
00:09:03,650 --> 00:09:05,190
that's when you start to see the smoothing

226
00:09:05,190 --> 00:09:07,350
scrolling that this approach allows.

227
00:09:07,350 --> 00:09:09,210
So the improvement in the smoothness

228
00:09:09,210 --> 00:09:10,559
of the scrolling can be readily,

229
00:09:10,559 --> 00:09:14,017
can be really evident on older devices as well.

230
00:09:14,017 --> 00:09:15,840
You can see that we still got it working now

231
00:09:15,840 --> 00:09:18,039
and we've added the summary again now.

232
00:09:18,039 --> 00:09:20,440
And you can see that it's working quite nicely.

233
00:09:20,440 --> 00:09:23,110
There's no perceivable delay there.

234
00:09:23,110 --> 00:09:24,920
But again you'd be more noticeable on an

235
00:09:24,920 --> 00:09:26,600
older Android device

236
00:09:26,600 --> 00:09:28,357
or if you're starting to use animations

237
00:09:28,357 --> 00:09:32,543
in the list view for animating various views.

238
00:09:33,670 --> 00:09:35,410
Alright now let's have a look at the log cat.

239
00:09:35,410 --> 00:09:36,710
And we'll click on log cat

240
00:09:37,580 --> 00:09:38,510
to open that up

241
00:09:39,901 --> 00:09:42,320
and we'll go back to our current again.

242
00:09:42,320 --> 00:09:43,453
Now as I scroll,

243
00:09:44,972 --> 00:09:48,480
we can see the convert views being used,

244
00:09:48,480 --> 00:09:50,173
get view provided a convert view.

245
00:09:53,627 --> 00:09:56,710
We get new views created to start with

246
00:09:56,710 --> 00:09:58,170
until the display fills up

247
00:09:58,170 --> 00:10:00,200
but after that we're reusing the old views

248
00:10:00,200 --> 00:10:03,780
that the list view passes back to get view.

249
00:10:03,780 --> 00:10:05,410
Alright so that's our improved adaptor.

250
00:10:05,410 --> 00:10:07,070
It now uses much less memory

251
00:10:07,070 --> 00:10:10,150
and works more efficiently than the first version.

252
00:10:10,150 --> 00:10:12,350
Now when you're creating your own adaptors,

253
00:10:12,350 --> 00:10:14,280
reuse the views that you're giving them back

254
00:10:14,280 --> 00:10:16,480
and use the view holder pattern to improve

255
00:10:16,480 --> 00:10:19,010
the responsiveness of your app.

256
00:10:19,010 --> 00:10:21,920
Now although Google recommends the view holder pattern

257
00:10:21,920 --> 00:10:24,120
it didn't enforce it's use with the list view.

258
00:10:24,120 --> 00:10:25,890
And when we come back to look at the new

259
00:10:25,890 --> 00:10:28,040
recycler view widget you'll see that the

260
00:10:28,040 --> 00:10:30,629
view holder pattern is enforced with that.

261
00:10:30,629 --> 00:10:33,570
Alright so I'm going to reformat this code.

262
00:10:33,570 --> 00:10:35,303
I'll close down the log cat first.

263
00:10:39,181 --> 00:10:42,813
And what I'm also going to do is change the,

264
00:10:42,813 --> 00:10:44,820
I'll go back to main activity,

265
00:10:44,820 --> 00:10:46,540
and I'm going to change the limit that was set

266
00:10:46,540 --> 00:10:50,533
to 200 back to ten just in case that will

267
00:10:50,533 --> 00:10:52,100
prevent 200 items from

268
00:10:52,100 --> 00:10:53,434
accessed in the future.

269
00:10:53,434 --> 00:10:55,850
Now if you want to learn more about list views

270
00:10:55,850 --> 00:10:58,410
and adapters then the talks from Google I/O

271
00:10:58,410 --> 00:11:00,200
are available on YouTube

272
00:11:00,200 --> 00:11:02,050
and these are highly recommended as they're

273
00:11:02,050 --> 00:11:03,729
technical talks presented by the people

274
00:11:03,729 --> 00:11:06,124
who create the Android code.

275
00:11:06,124 --> 00:11:09,626
Now each year since 2008 Google have run Google I/O

276
00:11:09,626 --> 00:11:12,508
to present the new technologies that they've created.

277
00:11:12,508 --> 00:11:15,820
And it's largely devoted to technical presentations

278
00:11:15,820 --> 00:11:17,190
covering things like Android

279
00:11:17,190 --> 00:11:18,210
and Chrome,

280
00:11:18,210 --> 00:11:20,070
and it's a great way to learn about what Google

281
00:11:20,070 --> 00:11:21,620
has planned for the future

282
00:11:21,620 --> 00:11:23,042
as well as getting information on their current

283
00:11:23,042 --> 00:11:26,650
technologies from the programmers who create them.

284
00:11:26,650 --> 00:11:30,060
And there's actually a talk on list views

285
00:11:30,060 --> 00:11:32,272
and adapters from the 2010 Google I/O.

286
00:11:32,272 --> 00:11:34,323
I'm just going to give you a link there.

287
00:11:35,196 --> 00:11:36,710
And this will be in the resources section.

288
00:11:36,710 --> 00:11:38,950
A very useful video to check out

289
00:11:38,950 --> 00:11:39,900
and have a look at.

290
00:11:43,288 --> 00:11:44,307
And I won't actually start playing it now

291
00:11:44,307 --> 00:11:47,080
but you can see that it's obviously a

292
00:11:47,080 --> 00:11:47,913
popular video

293
00:11:47,913 --> 00:11:49,120
and there's a lot of people who subscribe

294
00:11:49,120 --> 00:11:49,953
to this channel.

295
00:11:49,953 --> 00:11:51,570
So very much worthwhile watching this video

296
00:11:51,570 --> 00:11:53,300
to understand a lot more about list views

297
00:11:53,300 --> 00:11:54,740
and adapters.

298
00:11:54,740 --> 00:11:55,960
Alright so in the next video

299
00:11:55,960 --> 00:11:57,410
we're going to add a menu to the app

300
00:11:57,410 --> 00:11:59,110
so that we can choose form a selection of

301
00:11:59,110 --> 00:12:01,938
feeds rather than just displaying the same one.

302
00:12:01,938 --> 00:12:03,433
See you in the next video.

