1 00:00:05,200 --> 00:00:09,390 In the last video we found out more about what this ContentResolver is. 2 00:00:09,430 --> 00:00:13,570 So back to our code now. We're going to use this applications ContentResolver. 3 00:00:13,810 --> 00:00:19,110 As I said there's just a single instance of the ContentResolver, and it's responsible for resolving 4 00:00:19,200 --> 00:00:26,120 all requests for content by directing the requests to the appropriate Content Provider. Now in our code down 5 00:00:26,130 --> 00:00:33,630 here on line 25 where we call contentResolver.query, the ContentResolver extracts the Authority 6 00:00:33,690 --> 00:00:39,900 from the URI and uses that to decide which Content Provider it should send the query request 7 00:00:39,900 --> 00:00:40,670 to. 8 00:00:40,980 --> 00:00:47,660 It then gets a cursor back from that Content Provider and returns the cursor to our calling code. 9 00:00:47,660 --> 00:00:51,840 Alright so we're going to write a bit more code now and we're going to store the contacts in a list. 10 00:00:51,920 --> 00:00:52,880 So let's start by doing that. 11 00:00:52,870 --> 00:00:59,500 So below the line now where we've retrieved our cursor, we're going to add some more code. So what we're going to do 12 00:00:59,500 --> 00:01:08,010 first is add a new line and then we're going to put val contacts is equal to ArrayList. And then we're going to 13 00:01:08,010 --> 00:01:12,090 use the diamond operate with string, so that's the type string we're getting back, 14 00:01:12,150 --> 00:01:15,710 or at least what's going to be in the ArrayList and parentheses on the end. 15 00:01:15,960 --> 00:01:16,880 And just a note there. 16 00:01:16,920 --> 00:01:23,460 That's basically going to be "create a list to hold our contacts". 17 00:01:23,600 --> 00:01:24,270 Alright. 18 00:01:24,270 --> 00:01:30,640 Then on the next line we do cursor question-mark dot use, left and right 19 00:01:30,680 --> 00:01:36,050 curly braces. And we'll just put a note here, 20 00:01:36,510 --> 00:01:37,050 "loop through 21 00:01:43,280 --> 00:01:50,900 the cursor". OK, so within the block itself, this time we're going to use while parentheses. We're going to use it this time 22 00:01:50,900 --> 00:01:56,470 correctly, so it.moveToNext closing parentheses. 23 00:01:56,670 --> 00:02:03,070 Open a code block again, then we do a contacts, which is our ArrayList dot add parentheses. 24 00:02:03,320 --> 00:02:13,230 it.getString. Then in parentheses again we're going to put it.getColumnIndex parentheses again, 25 00:02:13,460 --> 00:02:20,480 ContactsContract.Contacts. Then it's going to be dot DISPLAY_NAME_PRIMARY, 26 00:02:20,530 --> 00:02:25,670 then we've got three closing right parentheses at the end of the line. 27 00:02:25,670 --> 00:02:30,830 Alright so we're storing the contacts in a list which I've called contacts, and we're adding each contact to the list 28 00:02:31,190 --> 00:02:34,060 and we'll use the list shortly as the data for an adapter. 29 00:02:34,310 --> 00:02:37,010 Now we can't guarantee that we'll get any data back. 30 00:02:37,220 --> 00:02:40,420 So we're using the safe call operator before the use function 31 00:02:40,490 --> 00:02:41,890 with a question-mark. 32 00:02:41,900 --> 00:02:47,510 Now the call to use and the while loop use the same approach that we've used in our earlier example. 33 00:02:47,870 --> 00:02:51,040 Using a cursor is the same, even though we're now getting the data back 34 00:02:51,050 --> 00:02:54,290 via a ContentResolver and ContentProvider. 35 00:02:54,770 --> 00:02:59,840 So the last thing we need to do now in this code to read the data, is to create an adapter for the 36 00:02:59,840 --> 00:03:00,660 ListView. 37 00:03:00,800 --> 00:03:02,180 So let's go ahead and do that. 38 00:03:02,200 --> 00:03:05,090 I'm going to put that immediately below the line we've just finished typing. 39 00:03:05,180 --> 00:03:14,120 So we're going to type val adapter is equal to, we're going to type ArrayAdapter, then a diamond operator, string 40 00:03:14,120 --> 00:03:17,570 in the middle of that, so type string. Then parentheses 41 00:03:17,930 --> 00:03:31,750 this comma R.layout.content_detail comma then R.id.name comma then contacts being our 42 00:03:31,750 --> 00:03:35,340 ArrayList. Then next we're going to do contact 43 00:03:35,420 --> 00:03:47,660 underscore names.adapter equals adapter. Now by the way if you are asked to select the import for contact 44 00:03:47,660 --> 00:03:54,390 underscore names, choose a synthetic import, and that's Kotlin X dot android.synthetic.main.content underscore 45 00:03:54,400 --> 00:03:56,900 main dot star. 46 00:03:57,110 --> 00:04:00,170 And you can see in my case there, because I've got auto-imports on, 47 00:04:00,170 --> 00:04:06,720 it's found that, well processed that automatically for us. Alright, so moving on. And by the way we've seen this code before 48 00:04:07,110 --> 00:04:10,530 in the top 10 downloader app for the ArrayAdapter. 49 00:04:10,760 --> 00:04:13,390 Alright so at this point the code's completed, almost. 50 00:04:13,680 --> 00:04:16,070 What we still need to deal with though is permissions. 51 00:04:16,250 --> 00:04:19,560 So Google changed the way permissions work with Android Marshmallow. 52 00:04:19,769 --> 00:04:24,930 So I want to spend a bit of time discussing that. Now we should really finish off what we're doing with 53 00:04:24,930 --> 00:04:27,760 these ContentResolvers and ContentProviders first, though. 54 00:04:28,050 --> 00:04:30,680 So what I'm going to do is run this on an Android lollipop, 55 00:04:30,720 --> 00:04:34,010 the API 21 emulator, so that we can see it working. 56 00:04:34,110 --> 00:04:37,810 But then in the next video we're going to spend some time looking at permissions. 57 00:04:37,920 --> 00:04:42,930 Whichever version of Android we use, we still need to request the permissions in the Android manifest 58 00:04:42,930 --> 00:04:44,370 at least, for the app. 59 00:04:44,380 --> 00:04:46,050 So let's go ahead and do that. 60 00:04:46,140 --> 00:04:53,140 So we're going to open the project on the left, we're going to open up manifest. 61 00:04:53,260 --> 00:04:56,920 So the permission we want here is READ_CONTACTS, so let's go ahead and do that. 62 00:04:56,920 --> 00:05:03,490 So we're going to come down here above the application tag and we'll create, or we'll add rather, a user's 63 00:05:03,580 --> 00:05:05,330 permission tag here. 64 00:05:05,640 --> 00:05:10,870 You can see that Android Studio is helpfully helping, or filling that in for us. And the one we want, 65 00:05:10,870 --> 00:05:16,390 as I mentioned, is READ_CONTACTS, so I'm just specifying that and pressing enter 66 00:05:16,420 --> 00:05:21,150 so there's no chance of me accidentally mistyping that. So I'm going to close off the tag there, so 67 00:05:21,160 --> 00:05:26,980 we've got the permission now set up for reading contacts defined in our Android Mainfest file. 68 00:05:27,370 --> 00:05:32,240 So once we've done this now the app should work on any version of Android before API 23. 69 00:05:32,590 --> 00:05:36,320 So let's run it on the API 21 device that we set up a few videos ago. 70 00:05:39,490 --> 00:05:42,560 So this is the one here that I set up, API 21 Contacts, so let's run that. 71 00:05:59,100 --> 00:06:03,140 Alright, so once the app is running, which it is now, we should be able to tap the floating action button 72 00:06:03,470 --> 00:06:05,760 and see the contacts displayed in the ListView. 73 00:06:05,800 --> 00:06:10,290 And just remember to choose the emulator that you've added the contacts to in the earlier video, 74 00:06:10,440 --> 00:06:13,960 otherwise of course you won't be able, or you won't have any contact records to display. 75 00:06:14,170 --> 00:06:20,450 So I'm going to click on the floating action button, and you can see we've got two records showing there. Now if we had enough 76 00:06:20,450 --> 00:06:25,000 records we could scroll through them, as you've seen us do with a ListView in earlier apps. 77 00:06:25,100 --> 00:06:26,750 In fact now we know that it's working, 78 00:06:26,780 --> 00:06:31,490 you could run it on your phone and you'll see all your contacts appear in the list. 79 00:06:31,490 --> 00:06:33,650 Alright but at this point that's working fine, 80 00:06:33,650 --> 00:06:37,310 and that's how we can use data using a Content Provider. 81 00:06:37,760 --> 00:06:42,980 Now obviously this is a very basic application, but it does give you the concepts of a Content Provider and 82 00:06:42,980 --> 00:06:45,530 also using a Content Resolver. 83 00:06:45,530 --> 00:06:50,660 In this case we were able to access the contacts built into the phone, and as you can see if we go back to the 84 00:06:50,660 --> 00:06:51,110 code, 85 00:06:57,320 --> 00:07:03,450 the actual code to query the data is very similar to what we had when we accessed the database directly. 86 00:07:03,470 --> 00:07:09,920 So using a Content Provider doesn't really introduce any more complexity into our code, beyond having 87 00:07:09,920 --> 00:07:16,040 to obtain the content_uri from the ContentProvider class, so that we can pass that to 88 00:07:16,040 --> 00:07:22,460 the Content Resolver. We query the Content Resolver, and that passes the query onto the Content Provider. 89 00:07:22,850 --> 00:07:29,120 The Content Provider then fetches the data from its data source or, in the case of an update, writes the 90 00:07:29,120 --> 00:07:35,600 data to the data source and either returns a cursor to the Content Resolver or reports back how many 91 00:07:35,600 --> 00:07:36,960 records were updated. 92 00:07:37,040 --> 00:07:41,710 There's a direct mapping of methods from a Content Resolver to the Content Provider. 93 00:07:41,870 --> 00:07:47,180 For example, when we call the Resolver's query method, that has to call a query method in the Provider, 94 00:07:47,540 --> 00:07:53,330 and the same applies to Inserts and Updates. Every method we call in the resolver has a corresponding method 95 00:07:53,660 --> 00:07:59,600 that the Resolver calls in the Provider, and we'll see that all in more detail when we come to create our own 96 00:07:59,600 --> 00:08:00,740 Content Provider. 97 00:08:00,970 --> 00:08:05,930 And in the next app we'll do just that, and we'll look at creating our own Content Provider to provide 98 00:08:05,930 --> 00:08:08,240 access to our apps database. 99 00:08:08,240 --> 00:08:13,970 Now this is more complex than just using the database directly, but it does mean that other apps will 100 00:08:14,000 --> 00:08:20,160 also be able to access the data in the same way as we've just done with the phone's contacts data. 101 00:08:20,280 --> 00:08:25,280 And it also frees us from having to cater for things like the activity life-cycle. We're not accessing 102 00:08:25,280 --> 00:08:30,680 the database directly, and don't have to worry about opening and closing it. The Content Resolvers object's 103 00:08:30,680 --> 00:08:34,669 global, and doesn't get destroyed when our activity does. 104 00:08:34,669 --> 00:08:38,770 Of course we still have to program our activity to handle its life-cycle events. 105 00:08:38,809 --> 00:08:41,750 If I rotate the emulator the ListView's cleared. 106 00:08:42,020 --> 00:08:46,830 So going back to the emulator, so as you can see if I rotate the device 107 00:08:46,830 --> 00:08:51,950 the ListView is cleared, and we have to click on the fab button to bring the data back again. 108 00:08:52,280 --> 00:08:57,050 So that does result in the query getting executed again unsurprisingly, then we'll be seeing how a 109 00:08:57,050 --> 00:08:59,780 loader can be used to prevent that though. 110 00:08:59,780 --> 00:09:05,300 The point I want to make though about the life-cycle, is that we don't have to concern ourselves with coordinating 111 00:09:05,300 --> 00:09:12,320 the data access with the activity life-cycle. The Content Resolver and Content Provider handle that all for 112 00:09:12,320 --> 00:09:13,060 us. 113 00:09:13,370 --> 00:09:18,920 If we query the database using a CursorLoader, we also don't have to worry about creating background 114 00:09:18,920 --> 00:09:22,260 threads, and we'll be saying how to do that in the next section. 115 00:09:22,640 --> 00:09:27,170 But coming up in the next video we're going to look at the changes that Google made to permissions in API 116 00:09:27,170 --> 00:09:32,190 23, and how to get this app working with Android Marshmallow and above. 117 00:09:32,230 --> 00:09:33,160 See you in the next video.