1 00:00:04,660 --> 00:00:07,930 Alright, so going on to the solution to 2 00:00:07,930 --> 00:00:09,280 the challenge that we talked about at 3 00:00:09,280 --> 00:00:11,230 the end of the last video, the first 4 00:00:11,230 --> 00:00:12,820 thing that we're going to do is add the 5 00:00:12,820 --> 00:00:15,339 refresh option to the menu. Now that's 6 00:00:15,339 --> 00:00:16,869 very simple - we're just going to drag a new 7 00:00:16,869 --> 00:00:19,630 item into the Design, to make sure that 8 00:00:19,630 --> 00:00:21,070 it's below the group and not a member of 9 00:00:21,070 --> 00:00:22,900 it. And we talked about that previously, 10 00:00:22,900 --> 00:00:27,789 so Menu Item, and you can either do it 11 00:00:27,789 --> 00:00:30,010 here or come down here. So it's easy to 12 00:00:30,010 --> 00:00:31,359 do it down here, in the Component Tree 13 00:00:31,359 --> 00:00:33,460 usually. And you can see there, that I've 14 00:00:33,460 --> 00:00:35,080 dragged it so it's actually in the wrong 15 00:00:35,080 --> 00:00:37,840 place, but I can move that out to make 16 00:00:37,840 --> 00:00:40,059 sure that it's no longer in the menu 17 00:00:40,059 --> 00:00:42,280 anymore, and no longer in the menu group 18 00:00:42,280 --> 00:00:45,250 anymore, which is what we want here. Next 19 00:00:45,250 --> 00:00:48,070 we want to change the ID. the ID is going 20 00:00:48,070 --> 00:00:54,100 to be a mnuRefresh, and the title, we'll 21 00:00:54,100 --> 00:00:57,460 make Refresh. Alright, so that's it for 22 00:00:57,460 --> 00:01:05,640 the menu and we'll go back to the code. 23 00:01:05,640 --> 00:01:08,770 Alright, so if we're going to track the URL, so 24 00:01:08,770 --> 00:01:10,420 that we can compare the previous one to 25 00:01:10,420 --> 00:01:11,500 the one that we're about to download, 26 00:01:11,500 --> 00:01:13,929 then we need a variable to store it in. 27 00:01:13,929 --> 00:01:16,479 Now we're also going to be storing the 28 00:01:16,479 --> 00:01:18,550 URL and Limit in a Bundle, so I'm going 29 00:01:18,550 --> 00:01:21,160 to define two constants to use as the keys. 30 00:01:21,160 --> 00:01:22,959 So I'm going to do that at the top of 31 00:01:22,959 --> 00:01:26,679 MainActivity, just below the feedLimit 32 00:01:26,679 --> 00:01:28,630 and feedUrl that we worked on in the 33 00:01:28,630 --> 00:01:30,940 last two videos. So we start with a 34 00:01:30,940 --> 00:01:38,979 private var feedCachedUrl is equal 35 00:01:38,979 --> 00:01:41,200 to, and we'll start with double quotes 36 00:01:41,200 --> 00:01:47,170 invalidated. Then private val STATE 37 00:01:47,170 --> 00:01:53,670 _URL is equal to feedUrl. Then 38 00:01:53,670 --> 00:01:58,060 private val STATE_LIMIT 39 00:01:58,060 --> 00:02:03,520 equals feedLimit. Now I've initialized 40 00:02:03,520 --> 00:02:06,700 the feedCachedUrl String to a value that 41 00:02:06,700 --> 00:02:09,669 can't possibly be a valid URL. Now 42 00:02:09,669 --> 00:02:11,260 anytime we want to force a download to 43 00:02:11,260 --> 00:02:13,660 happen, such as when the Refresh option 44 00:02:13,660 --> 00:02:15,880 is chosen from the menu, we just need to 45 00:02:15,880 --> 00:02:17,930 set it to some value that isn't a 46 00:02:17,930 --> 00:02:19,969 URL. Now anything would do, but I've 47 00:02:19,969 --> 00:02:22,700 just used the word INVALIDATED. Now to 48 00:02:22,700 --> 00:02:24,140 prevent the same URL from being 49 00:02:24,140 --> 00:02:25,609 downloaded unnecessarily, 50 00:02:25,609 --> 00:02:28,010 we just need to compare the cached URL 51 00:02:28,010 --> 00:02:30,140 value with the one that we're about to 52 00:02:30,140 --> 00:02:32,120 download. Now if they're the same, there's 53 00:02:32,120 --> 00:02:34,549 no need to download again. So let's go 54 00:02:34,549 --> 00:02:37,310 down to the downloadUrl function to 55 00:02:37,310 --> 00:02:43,430 do that. So down here, we're going to wrap 56 00:02:43,430 --> 00:02:45,109 this in some code, so we're going to put an 57 00:02:45,109 --> 00:02:49,459 if test here to say if parentheses feed 58 00:02:49,459 --> 00:02:55,480 Url is not equal to feedCachedUrl. 59 00:02:55,480 --> 00:02:57,769 We're going to wrap that code so we're 60 00:02:57,769 --> 00:03:00,650 going to copy this code, paste it in 61 00:03:00,650 --> 00:03:04,549 there. Okay, and I'm going to then put an 62 00:03:04,549 --> 00:03:09,040 else in there, so else Log.d 63 00:03:09,040 --> 00:03:16,939 parentheses TAG comma downloadUrl - URL 64 00:03:16,939 --> 00:03:21,560 not changed. So now with that code, when 65 00:03:21,560 --> 00:03:24,319 downloadUrl's called, it first checks 66 00:03:24,319 --> 00:03:26,419 the URL it's given against the stored 67 00:03:26,419 --> 00:03:28,639 value. Now if they're the same, then 68 00:03:28,639 --> 00:03:29,810 there's no need to download the data 69 00:03:29,810 --> 00:03:32,569 again - it just logs the fact so that we 70 00:03:32,569 --> 00:03:33,859 can see the code working in the logcat. 71 00:03:33,859 --> 00:03:36,229 But of course, if the URL's are different, 72 00:03:36,229 --> 00:03:37,400 then it's going to go through and execute 73 00:03:37,400 --> 00:03:40,189 normally. And importantly, the other thing 74 00:03:40,189 --> 00:03:41,840 we need to do is, we need to update the 75 00:03:41,840 --> 00:03:45,379 value at the end of that; feedCachedUrl 76 00:03:45,379 --> 00:03:50,540 is equal to feedUrl. So basically, after 77 00:03:50,540 --> 00:03:52,069 downloading the data as usual, we're 78 00:03:52,069 --> 00:03:53,540 storing the URL that's just been 79 00:03:53,540 --> 00:03:56,150 downloaded in the feedCachedUrl field, 80 00:03:56,150 --> 00:03:59,120 ready to be compared next time. Alright, 81 00:03:59,120 --> 00:04:02,599 so onto the Refresh menu option. Now all 82 00:04:02,599 --> 00:04:05,930 that has to do, is set feedCachedUrl to 83 00:04:05,930 --> 00:04:08,599 something different to the last URL. So 84 00:04:08,599 --> 00:04:09,799 that's pretty straightforward. So let's 85 00:04:09,799 --> 00:04:11,720 have a look at the option there - the 86 00:04:11,720 --> 00:04:14,930 onOptionsItemSelected. We're going to use 87 00:04:14,930 --> 00:04:16,548 the string INVALIDATED because we've 88 00:04:16,548 --> 00:04:18,529 used that before. So we're going to put 89 00:04:18,529 --> 00:04:20,870 this code here, outside of the R. 90 00:04:20,870 --> 00:04:23,509 id.mnu 10 and mnu 25 tests. 91 00:04:23,509 --> 00:04:29,120 R.id.mnuRefresh, arrow 92 00:04:29,120 --> 00:04:32,310 token. We're gonna put feedCachedUrl 93 00:04:32,310 --> 00:04:37,680 equals INVALIDATE. Alright, so I'm 94 00:04:37,680 --> 00:04:39,180 using that string INVALIDATE, well 95 00:04:39,180 --> 00:04:41,250 actually, INVALIDATED to be consistent. So 96 00:04:41,250 --> 00:04:43,500 using that string again, as that helps to 97 00:04:43,500 --> 00:04:45,719 document what we're doing. So the feedCached 98 00:04:45,719 --> 00:04:47,310 Url has been invalidated, 99 00:04:47,310 --> 00:04:49,080 so the download will then need to 100 00:04:49,080 --> 00:04:52,349 be performed again. Alright, so 101 00:04:52,349 --> 00:04:53,490 that's one part of the challenge 102 00:04:53,490 --> 00:04:56,069 completed. The app should now - shouldn't 103 00:04:56,069 --> 00:04:58,500 now - download the data again, if we select 104 00:04:58,500 --> 00:05:00,990 the same menu item again. So it's worth 105 00:05:00,990 --> 00:05:02,550 testing the app, at this point, to make 106 00:05:02,550 --> 00:05:05,039 sure the code works. If you leave testing 107 00:05:05,039 --> 00:05:06,960 until you've made loads of changes, it 108 00:05:06,960 --> 00:05:09,659 gets much harder to find bugs. You've got 109 00:05:09,659 --> 00:05:11,909 far more code to check through. Running 110 00:05:11,909 --> 00:05:13,469 your app after making each change is a 111 00:05:13,469 --> 00:05:15,389 good habit to get into, and really 112 00:05:15,389 --> 00:05:17,610 does make debugging a lot easier. So 113 00:05:17,610 --> 00:05:23,069 let's actually run this. I'm going to go 114 00:05:23,069 --> 00:05:29,520 back to portrait mode. 115 00:05:29,520 --> 00:05:32,819 Alright, so far. so good. The app loads 116 00:05:32,819 --> 00:05:34,380 the first URL fine, so that's a good 117 00:05:34,380 --> 00:05:34,770 start. 118 00:05:34,770 --> 00:05:37,410 So just to confirm that the menu still 119 00:05:37,410 --> 00:05:38,940 works, we'll try doing a different type - 120 00:05:38,940 --> 00:05:42,210 we'll do Songs. Well that still works - we 121 00:05:42,210 --> 00:05:44,370 still get the top 10 songs. Alright, I'm gonna 122 00:05:44,370 --> 00:05:47,280 open the logcat, and we're going to do a 123 00:05:47,280 --> 00:05:50,340 search, or we're going to, rather, select the 124 00:05:50,340 --> 00:05:53,910 same option again - Songs - and you can see 125 00:05:53,910 --> 00:05:55,729 here in the logcat; 126 00:05:55,729 --> 00:05:59,370 downloadUrl - URL not changed. So that's 127 00:05:59,370 --> 00:06:01,590 working as well. So things seem to be 128 00:06:01,590 --> 00:06:03,210 working pretty good, but to make sure 129 00:06:03,210 --> 00:06:05,430 that the app still uses the same URL and 130 00:06:05,430 --> 00:06:07,680 feed limit, after being rotated, we need 131 00:06:07,680 --> 00:06:09,930 to store the values of the URL and the 132 00:06:09,930 --> 00:06:11,849 feedLimit, when the Activity is 133 00:06:11,849 --> 00:06:13,860 destroyed. So let's go back add 134 00:06:13,860 --> 00:06:17,490 the code for that. And what I'm going to 135 00:06:17,490 --> 00:06:19,889 do is just put the cursor below the on 136 00:06:19,889 --> 00:06:23,360 OptionsItemSelected method function, 137 00:06:23,360 --> 00:06:26,009 and let's get Android Studio to 138 00:06:26,009 --> 00:06:27,930 generate the onSaveInstanceState 139 00:06:27,930 --> 00:06:30,389 function. So I'm going to do my Ctrl-O, 140 00:06:30,389 --> 00:06:33,870 and we want onSaveInstanceState. 141 00:06:33,870 --> 00:06:35,729 Now, remembering there's two versions 142 00:06:35,729 --> 00:06:37,710 of this function. We want the one 143 00:06:37,710 --> 00:06:39,240 that's just got a single parameter. That 144 00:06:39,240 --> 00:06:40,409 we're looking at currently - that's got 145 00:06:40,409 --> 00:06:41,639 two options, so I'm gonna press the down 146 00:06:41,639 --> 00:06:43,199 arrow to go to the second one with the 147 00:06:43,199 --> 00:06:45,710 single parameter. Press Enter. 148 00:06:45,710 --> 00:06:48,120 Alright, I've added that 149 00:06:48,120 --> 00:06:50,070 between the onOptionsItemSelected 150 00:06:50,070 --> 00:06:53,250 and onDestroy, so that onDestroy ends up 151 00:06:53,250 --> 00:06:56,909 being the last function in the class. So 152 00:06:56,909 --> 00:06:58,440 we're going to now write some code in 153 00:06:58,440 --> 00:06:59,630 there. So we're going to start by 154 00:06:59,630 --> 00:07:02,900 removing the question mark from Bundle. 155 00:07:02,900 --> 00:07:05,099 We're going to leave the super dot 156 00:07:05,099 --> 00:07:07,740 onSaveInstanceState line in. We're going 157 00:07:07,740 --> 00:07:14,639 to put outState.putString, and it's 158 00:07:14,639 --> 00:07:17,930 going to be STATE_URL comma 159 00:07:17,930 --> 00:07:22,500 then feedUrl. Then on the next line, out 160 00:07:22,500 --> 00:07:27,180 State.putString STATE_ 161 00:07:27,180 --> 00:07:31,919 LIMIT, feedLimit - and that shouldn't be 162 00:07:31,919 --> 00:07:34,500 a string, it should be an int. Let's 163 00:07:34,500 --> 00:07:35,699 change that to an it because, of course, 164 00:07:35,699 --> 00:07:39,630 feedLimit is a number. Okay, that fixes 165 00:07:39,630 --> 00:07:41,760 that. Now we saw code like that before, in 166 00:07:41,760 --> 00:07:42,990 the calculator app - it just 167 00:07:42,990 --> 00:07:44,430 stores our two fields so that we can 168 00:07:44,430 --> 00:07:46,590 call them back again, when the Activity's 169 00:07:46,590 --> 00:07:49,410 recreated. Now the bundle's passed in as a 170 00:07:49,410 --> 00:07:51,540 nullable type, but we know that it won't 171 00:07:51,540 --> 00:07:54,390 be null, and as a result, I changed the 172 00:07:54,390 --> 00:07:56,610 function signature by removing the 173 00:07:56,610 --> 00:07:59,250 question mark after Bundle. Now remember 174 00:07:59,250 --> 00:08:01,800 that data's stored in a Bundle using 175 00:08:01,800 --> 00:08:04,740 key/value pairs. We specify a key when 176 00:08:04,740 --> 00:08:06,870 saving something, and use the same key to 177 00:08:06,870 --> 00:08:08,730 get it back again. And we'll see that 178 00:08:08,730 --> 00:08:11,370 our two keys; STATE_URL and 179 00:08:11,370 --> 00:08:13,680 STATE_LIMIT, being used again 180 00:08:13,680 --> 00:08:16,320 when we retrieve the values shortly. Now 181 00:08:16,320 --> 00:08:17,880 when we saved and restored values 182 00:08:17,880 --> 00:08:20,550 previously, we used the onRestore 183 00:08:20,550 --> 00:08:21,990 InstanceState and function. 184 00:08:21,990 --> 00:08:24,180 Now in that app, though, we weren't doing 185 00:08:24,180 --> 00:08:25,980 anything in onCreate, other than 186 00:08:25,980 --> 00:08:28,650 inflating the calculator layout. So it's 187 00:08:28,650 --> 00:08:30,480 probably a good idea just to review the 188 00:08:30,480 --> 00:08:33,419 Activity Lifecycle. Alright, so on 189 00:08:33,419 --> 00:08:35,480 RestoreInstanceState is called after 190 00:08:35,480 --> 00:08:39,030 the onCreate method. However, we do the 191 00:08:39,030 --> 00:08:41,700 initial download in onCreate. So when the 192 00:08:41,700 --> 00:08:44,070 device is rotated, we need to retrieve 193 00:08:44,070 --> 00:08:46,370 the saved Bundle in the onCreate method, 194 00:08:46,370 --> 00:08:49,170 rather than in onRestoreInstanceState, 195 00:08:49,170 --> 00:08:51,210 because if we wait for onRestore 196 00:08:51,210 --> 00:08:52,830 InstanceState, we won't have the URL 197 00:08:52,830 --> 00:08:55,530 available when we need it. Alright, so 198 00:08:55,530 --> 00:08:57,120 when the Activity's first launched, there 199 00:08:57,120 --> 00:08:59,460 won't be a Bundle. But if the Activity's 200 00:08:59,460 --> 00:09:02,280 restarted because of device rotation, for 201 00:09:02,280 --> 00:09:04,500 example, then the Bundle passed to 202 00:09:04,500 --> 00:09:06,900 onCreate will be non-null, and we can restore 203 00:09:06,900 --> 00:09:08,970 our fields there. So let's actually write 204 00:09:08,970 --> 00:09:11,130 some code now, in the onCreate method, to 205 00:09:11,130 --> 00:09:14,430 achieve this. So there's our onCreate 206 00:09:14,430 --> 00:09:15,660 method and we're going to put some code 207 00:09:15,660 --> 00:09:18,300 after the last logging. Well, actually, 208 00:09:18,300 --> 00:09:20,010 what we'll do is we'll put it after the 209 00:09:20,010 --> 00:09:23,130 start. So we've got the super.on 210 00:09:23,130 --> 00:09:26,490 Create and the setContentView. We'll put 211 00:09:26,490 --> 00:09:28,790 another log entry there, Log.d 212 00:09:28,790 --> 00:09:35,490 TAG parentheses onCreate called, and 213 00:09:35,490 --> 00:09:36,570 then we're going to put our code in here; 214 00:09:36,570 --> 00:09:40,470 if parentheses savedInstanceState is 215 00:09:40,470 --> 00:09:44,460 not equal to null. Add the code block, then 216 00:09:44,460 --> 00:09:47,700 we're going to put feedUrl is equal to 217 00:09:47,700 --> 00:09:52,620 savedInstanceState.getString. Then it's 218 00:09:52,620 --> 00:09:55,340 going to STATE_URL. Then it's going to 219 00:09:55,340 --> 00:09:59,660 be feedLimit is equal to savedInstance 220 00:09:59,660 --> 00:10:04,550 State.getInt STATE_ 221 00:10:04,550 --> 00:10:09,860 limit. Now when we're dealing with the 222 00:10:09,860 --> 00:10:12,140 Bundle in onCreate, we have to cater 223 00:10:12,140 --> 00:10:14,180 for it being null, and that's because it 224 00:10:14,180 --> 00:10:16,190 definitely will be, at least some of the 225 00:10:16,190 --> 00:10:18,860 time. Now I know Kotlin tries to do away 226 00:10:18,860 --> 00:10:20,630 with null checks but sometimes they're 227 00:10:20,630 --> 00:10:23,690 valid, even in Kotlin. So here, null is a 228 00:10:23,690 --> 00:10:26,570 valid value for the Bundle. It signifies 229 00:10:26,570 --> 00:10:28,820 that there's nothing to restore. Now 230 00:10:28,820 --> 00:10:30,350 because we've performed a null check, 231 00:10:30,350 --> 00:10:33,589 Kotlin can perform a smart cast. So saved 232 00:10:33,589 --> 00:10:36,350 InstanceState is cast to be an non-null 233 00:10:36,350 --> 00:10:38,630 Bundle, and we don't have to use the safe 234 00:10:38,630 --> 00:10:40,610 call operator when accessing the get 235 00:10:40,610 --> 00:10:43,610 String and getInt methods. Alright, so 236 00:10:43,610 --> 00:10:44,930 we're now ready to test the program to 237 00:10:44,930 --> 00:10:46,670 make sure it meets all the requirements 238 00:10:46,670 --> 00:10:48,980 of the challenge. So let's actually run 239 00:10:48,980 --> 00:10:51,140 this again. Actually, what I'll do is open up 240 00:10:51,140 --> 00:10:56,690 logcat and run it. If logcat doesn't 241 00:10:56,690 --> 00:10:57,890 clear for you, then you'll want to have 242 00:10:57,890 --> 00:10:59,120 cleared it, but you can see, in my 243 00:10:59,120 --> 00:11:00,410 case, it did and then we've got the data - 244 00:11:00,410 --> 00:11:03,530 we've got the logcat showing. So 245 00:11:03,530 --> 00:11:05,390 let's first check a few URLs with 246 00:11:05,390 --> 00:11:07,339 different limits, to make sure we haven't 247 00:11:07,339 --> 00:11:09,470 broken anything that was working. So 248 00:11:09,470 --> 00:11:14,480 I'm gonna go back to the emulator. So we've 249 00:11:14,480 --> 00:11:16,310 got the Top 10 feeds in there, so that's 250 00:11:16,310 --> 00:11:18,320 a good start, and you can see that we've 251 00:11:18,320 --> 00:11:22,740 got the 10 entries in there. 252 00:11:22,740 --> 00:11:25,080 Okay, so that's working alright. Let's now 253 00:11:25,080 --> 00:11:29,510 change that and go for a limit of 25. 254 00:11:29,510 --> 00:11:32,750 Okay, clearly we've got more apps showing 255 00:11:32,750 --> 00:11:34,580 here, so that's working okay as well - 256 00:11:34,580 --> 00:11:37,220 the Top 25. If I go ahead and choose 257 00:11:37,220 --> 00:11:40,460 Songs now, we should get 25 songs, and 258 00:11:40,460 --> 00:11:42,590 that's because the Top 25 was 259 00:11:42,590 --> 00:11:46,370 selected, so click on Songs. And what we 260 00:11:46,370 --> 00:11:49,100 can do is just do a filter for Main 261 00:11:49,100 --> 00:11:54,110 Activity. You can see that the feed 262 00:11:54,110 --> 00:11:55,730 limit was set to 25 and it hasn't been 263 00:11:55,730 --> 00:11:57,920 reset since. Now if we have a look at the 264 00:11:57,920 --> 00:12:00,500 songs, clearly there's more than 10 there. 265 00:12:00,500 --> 00:12:02,330 So that seems to be working nicely as 266 00:12:02,330 --> 00:12:04,220 well. And in terms of the URL, if we 267 00:12:04,220 --> 00:12:08,750 go back and remove the filter, we can see 268 00:12:08,750 --> 00:12:11,420 here by looking in the XML, that clearly 269 00:12:11,420 --> 00:12:14,060 that it's talking about albums and so 270 00:12:14,060 --> 00:12:15,770 forth. So clearly thats Songs, so that's 271 00:12:15,770 --> 00:12:18,740 correct. Now while we've got a Top 25 feed, 272 00:12:18,740 --> 00:12:21,740 it's a good point, or a good time, to rotate 273 00:12:21,740 --> 00:12:22,910 the device to make sure it doesn't 274 00:12:22,910 --> 00:12:25,070 revert to the default Top 10, that it was 275 00:12:25,070 --> 00:12:28,220 doing before. So let's go back and rotate 276 00:12:28,220 --> 00:12:37,010 now. So have a look. It looks to me, we've 277 00:12:37,010 --> 00:12:38,180 still got two heaps of songs there so 278 00:12:38,180 --> 00:12:39,620 everything seems to be working nicely as 279 00:12:39,620 --> 00:12:41,990 well - we've got 25 songs there. Now if I 280 00:12:41,990 --> 00:12:43,880 scroll down a little bit more, we can see 281 00:12:43,880 --> 00:12:45,440 that it's definitely still the songs, and 282 00:12:45,440 --> 00:12:46,700 we can see those on the screen anyway, so 283 00:12:46,700 --> 00:12:49,130 that's working nicely. Now if we go back 284 00:12:49,130 --> 00:12:56,210 and choose songs again, and we can just 285 00:12:56,210 --> 00:12:58,940 do a filter here - MainActivity again - we 286 00:12:58,940 --> 00:13:00,890 can see that downloadUrl, URL is not 287 00:13:00,890 --> 00:13:03,350 changed, which is correct. So that's 288 00:13:03,350 --> 00:13:05,030 looking good and now the last check is 289 00:13:05,030 --> 00:13:08,090 to check Songs again, to make sure that 290 00:13:08,090 --> 00:13:09,710 the data is re-downloaded when the 291 00:13:09,710 --> 00:13:11,210 same type of feed is selected for the 292 00:13:11,210 --> 00:13:18,220 second time. So let's try that - Songs, 293 00:13:18,220 --> 00:13:21,400 and again, download URL not changed. So 294 00:13:21,400 --> 00:13:22,480 that's looking good as well. 295 00:13:22,480 --> 00:13:24,640 Now you may well have solved the challenge 296 00:13:24,640 --> 00:13:26,440 in a different way, but if it passes 297 00:13:26,440 --> 00:13:29,050 these tests, then well done! And 298 00:13:29,050 --> 00:13:30,520 everything's working, so that's the end 299 00:13:30,520 --> 00:13:32,140 of this section. Well, we've actually 300 00:13:32,140 --> 00:13:34,300 covered quite a lot in this section; so 301 00:13:34,300 --> 00:13:37,330 we used an AsyncTask to download data 302 00:13:37,330 --> 00:13:39,550 without blocking the main UI thread, and 303 00:13:39,550 --> 00:13:43,150 also used the built-in HTTP classes to 304 00:13:43,150 --> 00:13:45,490 download data from the internet. Then we 305 00:13:45,490 --> 00:13:47,170 looked at the supplied XML parser 306 00:13:47,170 --> 00:13:49,780 classes to parse XML from the downloaded 307 00:13:49,780 --> 00:13:52,390 data, and store the values we wanted in 308 00:13:52,390 --> 00:13:55,090 our own objects. Now the ListView widget's 309 00:13:55,090 --> 00:13:56,920 designed for displaying lists of data, 310 00:13:56,920 --> 00:13:59,050 and we saw how to connect that to a 311 00:13:59,050 --> 00:14:01,390 basic adapter. We then went further and 312 00:14:01,390 --> 00:14:03,940 created our own custom adapter, to give 313 00:14:03,940 --> 00:14:05,440 more control over how the data's 314 00:14:05,440 --> 00:14:07,600 displayed in the ListView. And we 315 00:14:07,600 --> 00:14:09,520 finished by creating our own menus and 316 00:14:09,520 --> 00:14:11,740 menu groups, and writing code to respond 317 00:14:11,740 --> 00:14:13,600 to the different menu items being 318 00:14:13,600 --> 00:14:16,540 selected. Alright, so now you have a 319 00:14:16,540 --> 00:14:18,550 basic app, you can have a go at changing 320 00:14:18,550 --> 00:14:20,830 things to improve it. So some ideas you 321 00:14:20,830 --> 00:14:22,350 might want to try at this point are; 322 00:14:22,350 --> 00:14:24,670 adding some more of the Apple feeds, such 323 00:14:24,670 --> 00:14:27,460 as the Albums or New Releases feeds. You 324 00:14:27,460 --> 00:14:29,530 could try parsing out the feed title 325 00:14:29,530 --> 00:14:31,960 from the downloaded XML, and displaying 326 00:14:31,960 --> 00:14:34,570 that in a TextView above the list, so that 327 00:14:34,570 --> 00:14:36,190 users have a reminder of which view 328 00:14:36,190 --> 00:14:38,080 they're seing. Perhaps you might want to 329 00:14:38,080 --> 00:14:40,120 try figuring out how to display the 330 00:14:40,120 --> 00:14:43,060 image URL in a text view, and searching 331 00:14:43,060 --> 00:14:44,410 on-line for how to make the links 332 00:14:44,410 --> 00:14:46,300 clickable, so that they open in the 333 00:14:46,300 --> 00:14:49,060 device's browser. Now it's helpful to 334 00:14:49,060 --> 00:14:51,100 watch these videos a few times, to really 335 00:14:51,100 --> 00:14:53,410 understand what's happening, and why we 336 00:14:53,410 --> 00:14:55,690 coded the app in this way. Now you'll 337 00:14:55,690 --> 00:14:57,220 find you pick up different things each 338 00:14:57,220 --> 00:14:59,740 time you watch the videos. Remember also, 339 00:14:59,740 --> 00:15:00,940 that there's a wealth of information 340 00:15:00,940 --> 00:15:03,490 available on-line, so if you're not sure 341 00:15:03,490 --> 00:15:05,230 how to do something, then a quick search 342 00:15:05,230 --> 00:15:07,180 will usually provide loads of 343 00:15:07,180 --> 00:15:09,460 information. Now the Google documentation 344 00:15:09,460 --> 00:15:11,830 is also very useful, even if most of the 345 00:15:11,830 --> 00:15:13,480 examples are currently written in Java, 346 00:15:13,480 --> 00:15:15,610 but I suspect over time, that will change 347 00:15:15,610 --> 00:15:17,950 and we'll start seeing Kotlin examples 348 00:15:17,950 --> 00:15:20,200 as well. So I'll stop the video here, and 349 00:15:20,200 --> 00:15:22,810 end this section, and in the next section 350 00:15:22,810 --> 00:15:24,250 we're going to create an app to view 351 00:15:24,250 --> 00:15:27,250 YouTube videos, using Google's YouTube 352 00:15:27,250 --> 00:15:31,530 API. See you in the next video.