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.