1 00:00:05,120 --> 00:00:07,340 So we're well on the way to getting this app finished. 2 00:00:07,410 --> 00:00:12,030 We just need some way now to pass the search results back to MainActivity. 3 00:00:12,050 --> 00:00:17,610 Now a good solution here would be to use something called shared preferences. Now shared preferences provides a way 4 00:00:17,610 --> 00:00:22,810 to store up data, so you can retrieve the data again next time the app starts up. 5 00:00:22,920 --> 00:00:27,540 They're not as powerful as a full database, but for many applications where you don't have to store 6 00:00:27,540 --> 00:00:33,490 a lot of data, they're ideal. And the other good thing is that they're also very easy to use, and they 7 00:00:33,500 --> 00:00:36,510 work in a similar way to the bundles that we've used before. 8 00:00:36,750 --> 00:00:41,910 So you store data in key value pairs, and retrieve the data items by specifying the key. 9 00:00:42,200 --> 00:00:47,520 So I'm going to add the code now to the onQueryTextSubmit function in search activity, just so you 10 00:00:47,570 --> 00:00:48,960 can see what it does. 11 00:00:52,830 --> 00:00:57,520 So onQueryTextSubmit, we're going to add code after the logging, 12 00:00:57,700 --> 00:01:12,380 and we'll start with val sharedPref equals PreferenceManager.getDefaultSharedPreferences, then parentheses, 13 00:01:12,410 --> 00:01:16,700 and it's going to be applicationContext. 14 00:01:16,700 --> 00:01:24,730 Then we're going to do sharedPref dot edit, we're actually calling the edit function, so there's parentheses dot putString 15 00:01:25,220 --> 00:01:28,730 parentheses, and it's going to be flickr query 16 00:01:28,980 --> 00:01:33,730 comma space query closing parentheses dot 17 00:01:33,820 --> 00:01:41,020 apply. We're calling the apply function, and then we're going to do searchView question mark dot 18 00:01:41,220 --> 00:01:47,390 clearFocus, and then we're going to leave the call to finish and then return true. 19 00:01:47,420 --> 00:01:53,840 So what we're doing here is starting out on line 41. We're getting a shared preferences object by calling the Preference 20 00:01:53,840 --> 00:01:58,960 Manager's getDefaultSharedPreferences function, passing it a context. 21 00:01:58,970 --> 00:02:04,550 Now here we want to pass the application context rather than using this, because the date is going to 22 00:02:04,550 --> 00:02:08,490 be retrieved by a different activity to the one that saved it. 23 00:02:08,539 --> 00:02:12,900 Now SearchActivity will store the data and MainActivity will retrieve it. 24 00:02:12,920 --> 00:02:19,250 Now we have to call the edit function on the next line, line 42, to put the shared preferences into a writable 25 00:02:19,250 --> 00:02:25,820 state, and then we use the, we call the putString function to store the search query string. 26 00:02:25,820 --> 00:02:31,420 Now we store the string using the flickr query constant that we defined in base activity as the key. Now 27 00:02:31,430 --> 00:02:36,980 MainActivity and SearchActivity can both use the same constant, which ensures that they're both using 28 00:02:36,980 --> 00:02:43,090 the same key when saving and retrieving the data, and the data's then installed when we call the apply function. 29 00:02:43,120 --> 00:02:46,410 Now it's not obvious why we need to call clear focus in there, 30 00:02:46,590 --> 00:02:51,530 and you wouldn't normally find out what problem it solves, unless you tested the app on a device with 31 00:02:51,530 --> 00:02:53,300 an external keyboard. 32 00:02:53,300 --> 00:02:55,120 Now fortunately our emulators 33 00:02:55,130 --> 00:03:00,380 can use the PC's keyboard, so you can spot the strange behavior if we leave that out. 34 00:03:00,380 --> 00:03:06,200 Now the problem it fixes, is if you type a search query, then use the keyboard's enter key to submit it. 35 00:03:06,200 --> 00:03:09,000 Now when you do that the search icon in MainActivity 36 00:03:09,050 --> 00:03:12,990 also receives a click event, and just launches search activity again. 37 00:03:13,010 --> 00:03:15,410 And in fact you saw me do that in the previous video, 38 00:03:15,560 --> 00:03:20,510 when I pressed enter, entering a search query before I ended up actually correctly pressing the arrow 39 00:03:20,570 --> 00:03:22,050 down the bottom right hand corner. 40 00:03:22,430 --> 00:03:27,140 So I'm going to leave you to comment that line out and try it, so you can see why we need to remove focus from 41 00:03:27,140 --> 00:03:30,090 the toolbar before returning to MainActivity. 42 00:03:30,160 --> 00:03:36,560 And remember that you'll only see the different behavior when you press enter on an external keyboard. Alright so 43 00:03:36,590 --> 00:03:37,970 to get the data back, 44 00:03:38,030 --> 00:03:42,510 we just read the same key from the shared preference when main activity resumes. 45 00:03:42,590 --> 00:03:48,630 So let's go back and edit the MainActivity onResume function, and put some code in there. So I'm going to 46 00:03:48,640 --> 00:03:52,350 leave the call to super onResume. On the next line we'll do val 47 00:03:52,820 --> 00:04:02,530 sharedPref is equal to, and its PreferenceManager.getDefaultSharedPreferences application context 48 00:04:02,530 --> 00:04:14,570 again. Then we're going to do val query result is equal to sharedPref.getString parentheses, and it's going to be 49 00:04:15,140 --> 00:04:21,410 flickr underscore query comma and two double quotes, closing parentheses. 50 00:04:21,540 --> 00:04:26,000 Next we're going to write a bit of code here. We're going to put if parentheses queryResult 51 00:04:26,000 --> 00:04:29,910 dot isNotEmpty, 52 00:04:30,100 --> 00:04:31,030 and we'll just add a blank 53 00:04:31,080 --> 00:04:33,830 code block for now. Then on the next line we're going to do some logging, 54 00:04:33,830 --> 00:04:40,970 so Log.d parentheses TAG comma double quotes dot onResume ends. 55 00:04:41,040 --> 00:04:44,990 So basically this is just the reverse of what we did to store the data. 56 00:04:45,230 --> 00:04:50,910 So we're creating a shared preferences object on line 120, using exactly the same code actually, 57 00:04:50,950 --> 00:04:56,310 then using the getString function to read the search string from the stored shared preferences on line 58 00:04:56,380 --> 00:04:59,060 21. Now there's no point downloading 59 00:04:59,100 --> 00:04:59,790 anything 60 00:04:59,960 --> 00:05:05,930 if no search criteria was specified, so we're checking to make sure the query result string isn't empty 61 00:05:06,230 --> 00:05:08,570 before attempting to download and parse the data. 62 00:05:08,580 --> 00:05:13,310 Or at least that's the code we're going to be using when we start filling that out from line 24. The getString 63 00:05:13,310 --> 00:05:16,730 function will attempt to retrieve the data stored with the key flickr query, 64 00:05:17,030 --> 00:05:22,930 but if it can't find the data with that key, it's going to return the second value we've passed it, an empty string 65 00:05:22,940 --> 00:05:26,260 in this case. So that's what this second argument's all about. 66 00:05:26,480 --> 00:05:32,790 Passing an empty string allows us to check to make sure we did get a search term from the user. OK. 67 00:05:32,910 --> 00:05:37,970 So if the user did specify something to search for, then we just repeat the code in onCreate to 68 00:05:37,970 --> 00:05:39,350 download the new data. 69 00:05:39,680 --> 00:05:41,430 And in fact we don't need to repeat it. 70 00:05:41,570 --> 00:05:44,230 We can just move that code into onResume. 71 00:05:44,240 --> 00:05:47,900 Remember that onResume's called after onCreate. 72 00:05:48,200 --> 00:05:53,600 So what I'm going to do is cut three lines from onCreate, and paste them into this empty if block in the 73 00:05:53,600 --> 00:05:58,770 onResume function. So back to onCreate. So the three lines 74 00:05:58,770 --> 00:05:59,700 that we want are these here, 75 00:05:59,720 --> 00:06:00,130 val 76 00:06:00,150 --> 00:06:04,790 url, the val getRawData and then the execute. So I'm going to copy those, 77 00:06:04,790 --> 00:06:11,350 or cut those rather. I'll just clear that up a little bit. Then go down to the resume, the 78 00:06:11,450 --> 00:06:13,360 onResume function. 79 00:06:13,360 --> 00:06:15,710 I'm going to paste that in here. 80 00:06:16,720 --> 00:06:18,890 So that's now called in the onResume function. 81 00:06:19,020 --> 00:06:24,070 And again, just to repeat, onResume's called after on Create. 82 00:06:24,120 --> 00:06:29,920 So therefore by putting it in onResume, we still guarantee that this code is going to be executed. 83 00:06:30,300 --> 00:06:37,170 Alright, so at this point all that remains to do, is to pass query result to the Create uri function, instead 84 00:06:37,170 --> 00:06:43,420 of the hardcoded string Android Oreo that we've currently got over here. 85 00:06:43,530 --> 00:06:47,640 So let's do that. Let's get rid of this, remove the hardcoded string there, 86 00:06:50,660 --> 00:06:53,670 and we're going to replace that instead with queryResult. 87 00:06:56,910 --> 00:06:58,500 Alright so that should work now, 88 00:06:58,500 --> 00:06:59,410 so let's test it. 89 00:07:04,980 --> 00:07:10,140 Now this time when I ran the app there's no data displayed, but that's because there wasn't any shared preference 90 00:07:10,140 --> 00:07:11,480 data to retrieve. 91 00:07:11,760 --> 00:07:16,440 So we have to do a search before we get any photo's returned. I'm going to go ahead and search for marshmallow 92 00:07:16,440 --> 00:07:17,330 again. 93 00:07:23,140 --> 00:07:27,620 And success as you can see there. We've got a load of photo's tagged now with marshmallow. 94 00:07:27,890 --> 00:07:31,540 Now we can narrow that down a little bit by searching for Android marshmallow. 95 00:07:31,820 --> 00:07:35,690 So let's try that, android comma marshmallow, 96 00:07:39,330 --> 00:07:41,990 and you can see we're getting some different results based on that as well, 97 00:07:45,770 --> 00:07:47,570 not particularly appropriate to Android marshmallow 98 00:07:47,610 --> 00:07:49,500 so let's just try another one to make sure. 99 00:07:49,670 --> 00:07:50,490 We'll try android 100 00:07:50,530 --> 00:07:50,950 nougat, 101 00:07:54,530 --> 00:08:00,290 and we've got some more computer related results there, android nougat showing. So clearly that's working fine. 102 00:08:00,300 --> 00:08:00,590 Alright. 103 00:08:00,600 --> 00:08:02,080 So that's great, 104 00:08:02,220 --> 00:08:06,860 but what happens if a user decides that they don't want to search though, and clicks the X to cancel. 105 00:08:06,880 --> 00:08:08,560 Let's try that. 106 00:08:08,590 --> 00:08:14,780 So if they're here and they decide that they don't want to proceed with a search, click on X. Now that's not good. 107 00:08:15,000 --> 00:08:18,680 It's closed the search view but it doesn't return to MainActivity. 108 00:08:18,870 --> 00:08:25,020 But we saw, if you recall, an onClose function in the documentation, so we can implement that listener 109 00:08:25,380 --> 00:08:30,000 and call finish if the user closes the search view instead of submitting a search. 110 00:08:30,320 --> 00:08:35,190 So let's go ahead and create that, or add that rather, to the onCreateOptionsMenu function in Search 111 00:08:35,190 --> 00:08:38,900 Activity. 112 00:08:39,080 --> 00:08:43,409 We want to add it down here, before the closing onCreateOptionsMenu 113 00:08:43,530 --> 00:08:46,610 log entry, so add it there. 114 00:08:46,610 --> 00:08:48,350 Let's add a bit of space. 115 00:08:48,890 --> 00:08:58,710 So I'm going to do searchView question mark dot, we're going to set an onCloseListener, like so, and the code we want to execute in 116 00:08:58,740 --> 00:09:02,440 there is finish and then false. 117 00:09:02,810 --> 00:09:07,840 So now that we've done that we should be able to run this, and then that method will be called back. 118 00:09:12,680 --> 00:09:19,530 So let's try that, let's go into search and this time we'll close, and it correctly goes back to MainActivity as 119 00:09:19,540 --> 00:09:23,030 you can see. That's fantastic, cancelling a search now works, 120 00:09:23,160 --> 00:09:28,980 and that's our app just about finished. But there is one thing we should probably add. Now to show what that is, 121 00:09:29,230 --> 00:09:30,990 I'm going to see firstly, by doing a search, 122 00:09:30,990 --> 00:09:36,200 it there's any photos of blue monkeys driving Porsche cars in a hurricane. 123 00:09:36,390 --> 00:09:44,220 So I'm going to use a search term, blue monkey, Porsche, hurricane 124 00:09:48,170 --> 00:09:54,450 search, and not surprisingly we don't get any photos appearing. Now in that scenario, 125 00:09:54,770 --> 00:09:59,450 it would be nice to show some sort of message to let the user know that no photos matched the query, 126 00:10:00,140 --> 00:10:02,770 and that'll actually let them know that the app's still working. 127 00:10:02,900 --> 00:10:04,420 It hasn't failed in some way. 128 00:10:04,620 --> 00:10:09,050 Now the easiest way to do that is to modify the recycler view adapter, 129 00:10:09,200 --> 00:10:11,630 and we're going to have to get it to fib slightly. 130 00:10:11,900 --> 00:10:16,640 So I'm going to finish the video here, and in the next one we'll see why it's sometimes necessary to 131 00:10:16,640 --> 00:10:18,550 get your classes to tell lies. 132 00:10:18,560 --> 00:10:19,520 See you in the next video.