1 00:00:05,660 --> 00:00:11,320 Our app's nearly finished. We just want to provide some sort of notification to the user if no photos match 2 00:00:11,320 --> 00:00:12,630 their search query. 3 00:00:12,910 --> 00:00:18,570 Now the class that provides the data to the recycler view for displaying, is our flickr recycler view 4 00:00:18,640 --> 00:00:19,910 adapter class. 5 00:00:19,930 --> 00:00:24,310 Now that's the easiest place to add a notification if there's nothing to display. 6 00:00:24,540 --> 00:00:32,070 So let's open up that class. 7 00:00:32,100 --> 00:00:37,890 Now the data's provided to the recycler view when it calls the onBindViewHolder function. 8 00:00:37,950 --> 00:00:42,710 So all we have to do is check the list of photos and provide a suitably formatted holder 9 00:00:42,900 --> 00:00:49,720 if there's nothing to display. Let's go ahead and do that, so on bind view holder. 10 00:00:49,910 --> 00:00:52,670 So what we're going to do is add some code here at the start. 11 00:00:52,690 --> 00:01:02,560 We're going to put if parentheses photoList.isEmpty closing parentheses and open a codeblock, and I'm 12 00:01:02,570 --> 00:01:11,450 going to do a holder dot thumbnail dot setImageResource parentheses. And it's going to be R dot 13 00:01:11,470 --> 00:01:25,100 drawerable.placeholder, and then we're going to put holder.title.text equals, in two double quotes, No photos 14 00:01:25,620 --> 00:01:26,620 match your criteria, 15 00:01:29,250 --> 00:01:31,870 or match your search is probably easier to understand. 16 00:01:31,870 --> 00:01:39,770 Full stop backslash n backslash n Use the search icon to search for photos. 17 00:01:42,560 --> 00:01:48,150 Then what we're going to do is change this at the end of the code block, code block and I'm going to put an else, and then another code block. 18 00:01:48,610 --> 00:01:53,580 Then we're going to put the rest of the code up to, but not including, that final line of the holder dot title 19 00:01:53,580 --> 00:02:00,960 dot text. We can put all this code in that code block. Paste it in there like so. 20 00:02:01,890 --> 00:02:05,810 So basically that's now only going to be executed on the else. 21 00:02:05,880 --> 00:02:12,270 So we're testing the photos first, and if it's null or contains no photos, we set the image to the placeholder 22 00:02:12,270 --> 00:02:15,120 image and provide an informative message in the photo's 23 00:02:15,120 --> 00:02:20,550 title text view. But if there is data we just execute the same code as before. 24 00:02:20,780 --> 00:02:27,960 Now the set image resource function that I'm calling here on line 43, that loads the placeholder 25 00:02:27,960 --> 00:02:30,890 image from the resources and puts it into the image view. 26 00:02:31,040 --> 00:02:36,590 Now these backslash n characters, slash n slash n characters, they represent line breaks, and they're 27 00:02:36,600 --> 00:02:38,670 a simple way to format text. 28 00:02:38,700 --> 00:02:44,040 So Kotlin will replace the backslash n with a newline character when the text is displayed. 29 00:02:44,040 --> 00:02:47,810 Now we've got this warning over here about a hardcoded string, 30 00:02:47,970 --> 00:02:50,620 and we really should put that into a string resource. 31 00:02:50,790 --> 00:02:55,200 And as we saw in a previous video, Android Studio does make that very easy for us. 32 00:02:55,260 --> 00:03:01,700 So I'm just going to click on the text, like so, and do alt enter. Then I can come over here and use the lightbulb. 33 00:03:01,870 --> 00:03:05,730 Now we saw that working earlier but at the moment it's not working here. 34 00:03:06,000 --> 00:03:09,190 Now that's annoying but it's possibly not a bad thing. 35 00:03:09,430 --> 00:03:15,510 Over-reliance on the code generators can lead to us not understanding the code, and it is useful to be 36 00:03:15,510 --> 00:03:17,910 able to do things without using the code generator. 37 00:03:17,910 --> 00:03:20,270 And yes I'm trying to be positive about this. 38 00:03:20,310 --> 00:03:23,720 Sometimes things just don't work until Google releases a fix. 39 00:03:23,790 --> 00:03:28,130 Now I may be trying to be positive about this problem, but don't think I'm making light of it. 40 00:03:28,230 --> 00:03:32,440 When you're learning about all this, it can be very hard to work out if you're doing something wrong. 41 00:03:32,550 --> 00:03:34,920 Most of the time you will be doing something wrong. 42 00:03:35,040 --> 00:03:40,680 Bugs like this are actually quite rare, but when they do happen they can be very frustrating. 43 00:03:40,680 --> 00:03:45,280 Now one thing that may help is to focus on what you're really trying to achieve. 44 00:03:45,420 --> 00:03:50,700 Are we trying to get Android Studio to create a string resource for us, or do we just want to use a 45 00:03:50,700 --> 00:03:54,810 string resource. So it would be nice if Android Studio did it for us, 46 00:03:54,810 --> 00:03:56,060 but that's not our aim here. 47 00:03:56,160 --> 00:04:00,700 Our aim is to remove those warnings and get the text into a resource. 48 00:04:00,900 --> 00:04:04,110 So I'm not going to fight the tool here. We'll end up getting frustrated. 49 00:04:04,400 --> 00:04:08,690 Instead what I'm going to do is cut the text out of the code, leaving the speech marks, like 50 00:04:08,710 --> 00:04:16,790 so. Then I'm going to go to my strings.xml file, which is in our res folder and then the value 51 00:04:16,790 --> 00:04:17,740 subfolder. 52 00:04:18,060 --> 00:04:19,320 Double click on that. 53 00:04:19,320 --> 00:04:25,890 We're going to add it right at the end here, and we're going to put, open a string tag, so string name equals, 54 00:04:27,000 --> 00:04:28,530 and we'll call it empty underscore 55 00:04:28,690 --> 00:04:38,190 photo, close the tag and I'm going to paste in the string, and you saw that pasting in text that contains 56 00:04:38,260 --> 00:04:40,450 line breaks doesn't always work too well. 57 00:04:40,490 --> 00:04:46,610 So if you get the text split over several lines as I have, then just remove those extra lines. 58 00:04:46,880 --> 00:04:50,730 Basically just delete the line breaks and type in the slash in manually. So I'm going to go ahead and do that 59 00:04:52,590 --> 00:04:57,150 and put in my two backslash n's there like so, and we're good to go there. 60 00:04:57,400 --> 00:05:00,640 Now the next thing is to change the code to use the resource. 61 00:05:00,690 --> 00:05:05,810 So go back to our flickr recycler view adapter and to our onBindViewHolder method. 62 00:05:06,080 --> 00:05:08,510 So we want to change this code now to use the resource. 63 00:05:08,610 --> 00:05:14,280 Now we can't do that by signing directly to the text property, but we can pass a resource ID to the set 64 00:05:14,280 --> 00:05:19,080 text function, and that's easier than trying to get a resource object and extracting the string from 65 00:05:19,080 --> 00:05:27,810 the resources. Now that worked fine in an activity, but isn't so easy in our adapter class. So I'm going to type, inside 66 00:05:27,820 --> 00:05:28,980 the double quotes, holder dot 67 00:05:28,990 --> 00:05:38,280 title. We can't use dot text, we use dot setText, parentheses R.string.empty underscore 68 00:05:38,310 --> 00:05:39,040 photo. 69 00:05:39,450 --> 00:05:42,260 So even without Android Studio's help that wasn't too hard. 70 00:05:42,480 --> 00:05:44,930 There's really no excuse for hardcoding strings in your code. 71 00:05:44,940 --> 00:05:46,260 That's the bottom line. 72 00:05:46,290 --> 00:05:51,690 Alright so that should work, but the recycler view calls the getItemCount function to check if there's 73 00:05:51,690 --> 00:05:54,580 any data to display, and it does that a lot. 74 00:05:54,660 --> 00:06:01,860 So often in fact, that we commented out the logging in that function to keep the log cat a bit tidier. 75 00:06:02,090 --> 00:06:05,850 This is the getItemCount, you can see that we've commented out the logging. 76 00:06:05,850 --> 00:06:09,440 Now if there's no data, getItemCount will return 0, 77 00:06:09,670 --> 00:06:12,120 and the recycler view won't attempt to display anything. 78 00:06:12,460 --> 00:06:18,940 So we have to get our adapter to fib and tell he recycler view that there is at least one data item for it 79 00:06:18,940 --> 00:06:20,310 to display. 80 00:06:20,320 --> 00:06:23,460 Now the recycler view won't know or care that it's not a real flickr photo. 81 00:06:23,570 --> 00:06:27,300 It'll just know that there's one item, and will go ahead and display it. 82 00:06:27,310 --> 00:06:29,480 So let's actually add some code for that. 83 00:06:29,500 --> 00:06:30,330 So on this line here, 84 00:06:30,400 --> 00:06:33,920 all we're going to do is change the 0 to a 1. 85 00:06:34,750 --> 00:06:40,360 So now if no photos match the tags that we search for, we get the placeholder image and a message. 86 00:06:40,910 --> 00:06:45,850 Now that previous search for the Porsche driving monkeys should still be saved. 87 00:06:45,850 --> 00:06:48,060 So let's run the app and see what happens. 88 00:06:52,690 --> 00:06:57,690 So as you can see when I run the app, there still aren't any, and we're now getting this message and the placeholder 89 00:06:57,700 --> 00:06:58,420 image. 90 00:06:58,570 --> 00:07:01,710 So that's a better user experience than the blank screen we had before, 91 00:07:01,850 --> 00:07:04,370 and it's actually well worth the extra effort to code it. 92 00:07:04,420 --> 00:07:07,350 Alright so that's the end of this section. 93 00:07:07,470 --> 00:07:09,710 So we've covered a lot of ground in this section. 94 00:07:09,750 --> 00:07:15,360 We had to look at a different way to use async tasks to download data from the internet, then parse the json 95 00:07:15,360 --> 00:07:19,920 data rather than the xml that we used in the top 10 downloader app. 96 00:07:20,070 --> 00:07:25,260 Now the downloading and parsing involved using callback functions to notify the calling process that data 97 00:07:25,260 --> 00:07:26,730 was available. 98 00:07:26,730 --> 00:07:27,480 Now in the process, 99 00:07:27,490 --> 00:07:32,820 we created our own interfaces for classes to implement, so that they could reliably provide callback 100 00:07:32,820 --> 00:07:35,600 functions to the async classes. 101 00:07:35,600 --> 00:07:41,520 And then we looked at using the recycler view, and recvcler view adapter classes, to display the data in 102 00:07:41,520 --> 00:07:43,560 a scrolling list on the device. 103 00:07:44,010 --> 00:07:46,700 And in order to view the photos at a larger size, 104 00:07:46,860 --> 00:07:51,590 we had to use a gesture detector to work out what kind of input we were getting from the user. 105 00:07:51,900 --> 00:07:57,700 And we responded to taps and long presses, while still allowing scroll events to be handled by the system. 106 00:07:58,080 --> 00:08:02,910 We then had a good look at material design, before using it to style our flickr browser app, 107 00:08:03,030 --> 00:08:07,770 along material design lines. Now in order to do that we had to learn about themes and styles, 108 00:08:08,160 --> 00:08:11,630 and keeping a consistent look across different versions of Android. 109 00:08:12,110 --> 00:08:17,010 And we finished off by looking at using string resources, rather than hardcoding text into our code 110 00:08:17,160 --> 00:08:18,310 and layouts. 111 00:08:18,510 --> 00:08:23,460 And finally we added a search feature to the app so that we could download different photos by specifying 112 00:08:23,460 --> 00:08:25,230 different tags to select them. 113 00:08:25,320 --> 00:08:26,870 So again that's the end of this section. 114 00:08:26,920 --> 00:08:28,300 I'll see you in the next one.