1 00:00:05,390 --> 00:00:11,500 In the previous video we created the layouts to display the contact records using a ListView. 2 00:00:11,760 --> 00:00:15,750 Now it's time to write the code to retrieve the contact details. 3 00:00:15,780 --> 00:00:21,150 Now before we get into the coding there's been a change in the way the private access modifier works 4 00:00:21,150 --> 00:00:23,870 in Kotlin. When used on a top level object 5 00:00:23,880 --> 00:00:25,610 it used to mean package private. 6 00:00:25,800 --> 00:00:30,690 So that meant that any private constants we declared would be visible throughout the package. 7 00:00:30,690 --> 00:00:35,280 Now that would obviously cause problems with our log tags, because most of the Kotlin files we've created, 8 00:00:35,640 --> 00:00:39,100 or create, have a tag. But that's no longer the case, 9 00:00:39,190 --> 00:00:44,920 and when private is used for a top level object, it means private within the file it's in. 10 00:00:45,010 --> 00:00:50,040 But just to demonstrate what I mean, I'm going to create the usual tag string that we've been using so far 11 00:00:50,050 --> 00:00:57,090 throughout the course. That of course is in the, within the class. We're going to do a private val TAG in 12 00:00:57,090 --> 00:01:04,269 uppercase equals double quotes MainActivity. Now that results in a warning from Android Studio, 13 00:01:04,349 --> 00:01:07,400 because the name tag doesn't conform to the naming conventions. 14 00:01:07,400 --> 00:01:08,370 If I just come over here, 15 00:01:09,840 --> 00:01:15,500 you can see we've actually got two warnings. The first one is the TAG isn't being used which we'll rectify shortly. But the 16 00:01:15,500 --> 00:01:19,840 second one you can see there, it's not matching a particular file naming convention or the regular expression. 17 00:01:21,130 --> 00:01:25,760 So the change in the way that Kotlin treats private for top level objects, means that we can move our 18 00:01:25,760 --> 00:01:28,930 TAG outside the class and make it a const. So let's do that. 19 00:01:33,650 --> 00:01:36,910 So we'll do private - we need to make it a const now. 20 00:01:36,990 --> 00:01:41,100 And you can see now if you hover over the warning, we've only got the warning about the property TAG not being 21 00:01:41,100 --> 00:01:46,220 used at this point in our application. So basically this is now exactly what we want. 22 00:01:46,220 --> 00:01:52,410 TAG is now private to this file and it won't conflict with any private TAG constants in other files. 23 00:01:52,560 --> 00:01:54,020 Alright so on with the code. 24 00:01:54,230 --> 00:01:59,810 So we're going to put the code to access the contacts inside the onClick method of the floating action 25 00:01:59,810 --> 00:02:04,480 button, so this code here. So I'm going to delete that code first. 26 00:02:05,000 --> 00:02:10,460 I'm going to add some logging, so Log.d parentheses. 27 00:02:10,460 --> 00:02:21,250 I'm having a hard time typing today, TAG comma double quotes. We'll just put fab onClick colon starts. 28 00:02:21,280 --> 00:02:21,550 OK. 29 00:02:21,560 --> 00:02:28,310 So there's our log. Now we're going to start by cheating. I'm going to replace some code now with a declaration of a string 30 00:02:28,310 --> 00:02:28,990 array 31 00:02:29,000 --> 00:02:37,540 after this logging method. So it's going to be val projection equals, going to be arrayOf parentheses. 32 00:02:38,000 --> 00:02:46,920 And it's going to be ContactsContract.Contacts.DISPLAY_NAME_PRIMARY 33 00:02:47,330 --> 00:02:48,800 and closing right parentheses. 34 00:02:49,060 --> 00:02:53,960 Now that's cheating because I already knew which column stores the contacts name, but how would I have found 35 00:02:53,960 --> 00:02:59,120 this out if I didn't already know that. Now we've seen how to call up the documentation as I've outlined before. 36 00:02:59,390 --> 00:03:05,840 So I'll go ahead and do that by selecting the contacts in ContactsContract.Contacts, so this part 37 00:03:05,840 --> 00:03:09,400 here. Then open the quick documentation. 38 00:03:09,670 --> 00:03:15,010 So that's useful, and if we scroll down and have a bit of a look, we can see in the columns we eventually get to 39 00:03:15,010 --> 00:03:20,410 this DISPLAY_NAME_PRIMARY, the display name for the contact. But that only works if you 40 00:03:20,410 --> 00:03:23,570 already have the object name on the screen to click on unfortunately. 41 00:03:23,720 --> 00:03:28,510 Now if you want to find the documentation for something like accessing contacts data, your best friend 42 00:03:28,510 --> 00:03:30,140 is probably the Google search engine. 43 00:03:30,280 --> 00:03:32,840 So think of the key things about what you're trying to do, 44 00:03:32,910 --> 00:03:36,130 then google those words. Let's go and open up a browser. 45 00:03:37,060 --> 00:03:44,320 So in this case, probably would be appropriate to type something along the lines of android contacts content 46 00:03:44,320 --> 00:03:44,850 provider, 47 00:03:44,890 --> 00:03:49,470 because we're looking for the Content Provider for the Android contacts. Now 48 00:03:49,510 --> 00:03:53,650 obviously you could phrase that in a number of different ways. Unless you manage to come up with 49 00:03:53,650 --> 00:03:56,710 something really obscure, you should probably get some useful results. 50 00:03:56,920 --> 00:03:59,970 You can see here in my case, it's returned some interesting looking links. 51 00:04:00,070 --> 00:04:05,080 They all link, as you can see here, to developer.android.com, so they are the official source of 52 00:04:05,290 --> 00:04:08,090 documentation from Google for Android development. 53 00:04:08,130 --> 00:04:15,690 So I'm going to go to this first link up here, the one that links to Content Provider under topics. And it is 54 00:04:15,730 --> 00:04:20,980 definitely worth getting into the habit of checking out the Google documentation. They provide reference 55 00:04:20,980 --> 00:04:25,930 docs, which can be a bit dry and hard to read, as well as guides and training docs that are more tutorial 56 00:04:25,960 --> 00:04:27,010 style in nature. 57 00:04:27,160 --> 00:04:33,220 So this one's a guide document, and that'll show you more on how to access the contacts database via the Content 58 00:04:33,220 --> 00:04:34,080 Provider. 59 00:04:34,440 --> 00:04:37,950 Now by the way we're going to be looking at a lot of this stuff covered here in our next app - 60 00:04:38,140 --> 00:04:43,210 things like retrieving a single row, for example - but do take advantage of the Google documentation to 61 00:04:43,210 --> 00:04:45,820 learn more about how Android works in general. 62 00:04:45,940 --> 00:04:46,180 Alright. 63 00:04:46,180 --> 00:04:51,090 So I'm certainly not going to read all of this. Scrolling down a bit though, we can see that there's this diagram here showing 64 00:04:51,110 --> 00:04:57,280 how the contact details are organized. Then in the description below you down here, you can see that we've got Contacts 65 00:04:57,430 --> 00:05:04,990 Contract.Contacts, and it mentions here that it's a row or rows representing different people based on 66 00:05:04,990 --> 00:05:10,170 aggregations of raw contact rows. So for our purpose they probably sound ideal, 67 00:05:10,170 --> 00:05:11,500 so I'm going to click on that link now. 68 00:05:14,320 --> 00:05:16,250 That brings up the ContactsContract dot 69 00:05:16,270 --> 00:05:18,750 Contacts class here, 70 00:05:18,790 --> 00:05:23,710 as you can see. There's obviously a lot of information on the class. But all we're really after here at the 71 00:05:23,710 --> 00:05:27,460 moment are the column names we can use. So if we scroll down a little bit, 72 00:05:27,730 --> 00:05:32,930 you see we do get a list of the various columns and there's our trusty DISPLAY_NAME_PRIMARY 73 00:05:32,930 --> 00:05:39,400 field, column name. So it's not so much the names, or it's really, to be technically correct 74 00:05:39,400 --> 00:05:44,770 it's the constants that we should use when referring to the columns. Now the column names in the database aren't 75 00:05:44,770 --> 00:05:47,760 really of interest when using a Content Provider. 76 00:05:47,770 --> 00:05:52,960 In fact when you use a Content Provider, you're not interested in anything about the database. 77 00:05:52,960 --> 00:05:56,490 Now we know that Android uses sqlite to store the contact details, 78 00:05:56,740 --> 00:06:01,450 but Google may decide to change that in the future. As long as we use the constants defined in this 79 00:06:01,450 --> 00:06:02,330 class, 80 00:06:02,350 --> 00:06:07,510 it won't matter if they use a completely different database with totally different names for the fields. 81 00:06:07,540 --> 00:06:10,240 If they do that, they'll update this class, 82 00:06:10,390 --> 00:06:15,400 and because of those static column names being the same, everything 83 00:06:15,440 --> 00:06:17,980 will continue, or our code will continue to work. 84 00:06:18,370 --> 00:06:23,020 So this fourth entry in the table is DISPLAY_NAME_PRIMARY and that sounds like 85 00:06:23,030 --> 00:06:29,560 the field we want. Alright so back to our code now, and we now know where that DISPLAY_NAME_PRIMARY came from. 86 00:06:29,560 --> 00:06:30,850 Now this is where it gets fun - 87 00:06:31,090 --> 00:06:34,880 if dealing with multiple levels of abstraction is your idea of fun. 88 00:06:34,900 --> 00:06:37,780 So what I'm going to do is type the code in and explain what's going on. 89 00:06:38,170 --> 00:06:44,660 So after that val projection line we're going to do a val space cursor equals, 90 00:06:44,910 --> 00:06:54,460 and it's going to bet be contentResolver.query. In parentheses it's going to be ContactsContract.Contacts 91 00:06:55,030 --> 00:06:58,770 dot CONTENT_URI, this one down here. 92 00:06:59,540 --> 00:07:03,860 And I'm going to do comma and move to the next line. 93 00:07:03,930 --> 00:07:10,800 Then we're going to do projection comma, then we do null comma null comma. 94 00:07:11,350 --> 00:07:20,480 Then we're going to end up with ContactsContract.Contacts dot, then we're going to enter the DISPLAY underscore, 95 00:07:20,500 --> 00:07:26,420 or we'll select DISPLAY_NAME_PRIMARY. Then we'll just end this with another log entry - 96 00:07:26,460 --> 00:07:29,520 Log.d parentheses TAG comma double quotes 97 00:07:29,530 --> 00:07:33,030 fab onClick ends. 98 00:07:36,620 --> 00:07:42,630 Alright, so we get a contentResolver, in case you're wondering how this was accessed. We get that from the activity 99 00:07:42,640 --> 00:07:48,640 using the getContentResolver method, but because this is Kotlin, we can use the property directly instead 100 00:07:48,640 --> 00:07:49,610 of going through the getter. 101 00:07:49,610 --> 00:07:52,430 So that's how I've been able to use this contentResolver here. 102 00:07:52,810 --> 00:07:58,170 So the contentResolver's query function returns a cursor containing the data we want. 103 00:07:58,270 --> 00:08:02,500 So let's start now by looking at those parameters we passed to the query function. 104 00:08:02,520 --> 00:08:04,380 Now we've got something we can query for data; 105 00:08:04,420 --> 00:08:06,790 the contentResolver that returns a cursor. 106 00:08:07,000 --> 00:08:10,980 The parameters we're passing to the query method are firstly the uri, 107 00:08:11,240 --> 00:08:14,440 that's this first entry here. Now, 108 00:08:14,530 --> 00:08:19,340 so this somehow identifies the data source that we want to get data from. 109 00:08:19,360 --> 00:08:24,160 This could be a database and a table for example, but this code doesn't need to know where the data's 110 00:08:24,160 --> 00:08:25,750 coming from. At the moment 111 00:08:25,750 --> 00:08:27,290 we don't care about that either. 112 00:08:27,310 --> 00:08:31,990 Now we'll find out soon enough, but for now we're just going to accept that this uri identifies the 113 00:08:31,990 --> 00:08:33,419 source of our data. 114 00:08:33,640 --> 00:08:35,440 Next we've got projection. 115 00:08:35,440 --> 00:08:39,580 This is just a string array holding the names of the columns that we want to retrieve. 116 00:08:39,580 --> 00:08:43,390 Now we're just asking for the DISPLAY_NAME_PRIMARY here, or DISPLAY 117 00:08:43,390 --> 00:08:48,010 underscore NAME underscore PRIMARY here column here, but we could put more fields into the array if we want to. 118 00:08:48,280 --> 00:08:53,330 Next we've got selection - that's a string containing a filter to determine which rows are returned - and 119 00:08:53,330 --> 00:08:56,750 think of this as the WHERE clause in a SQL statement. 120 00:08:56,770 --> 00:09:02,730 In fact that's exactly what it is without the SQL keyword where, and in this scenario because we're passing 121 00:09:02,730 --> 00:09:03,020 null, 122 00:09:03,040 --> 00:09:07,530 we get all rows returned. selectionArgs is the next one and 123 00:09:07,550 --> 00:09:13,310 this is an array of values that will be used to replace placeholders in the selection string. 124 00:09:13,600 --> 00:09:20,410 So there are a number of advantages to using the selectionArg parameter to specify the values we want, and 125 00:09:20,410 --> 00:09:21,500 we will look at those. 126 00:09:21,720 --> 00:09:27,970 But basically your selection might be name equals question-mark and the selectionArgs could contain the 127 00:09:27,970 --> 00:09:29,510 single value bob. 128 00:09:29,740 --> 00:09:32,270 The query would then use the filter, the WHERE clause 129 00:09:32,440 --> 00:09:37,510 if you like, name equals Bob. Because we're not doing any filtering again, we're just parsing null 130 00:09:37,540 --> 00:09:38,790 for this as well. 131 00:09:38,960 --> 00:09:40,820 And the last entry is the sort order, 132 00:09:41,020 --> 00:09:45,010 and this is just a string containing the names of the fields you want the data sorted by. 133 00:09:45,330 --> 00:09:46,450 So it's just a sequel 134 00:09:46,480 --> 00:09:52,720 ORDER BY clause, without the actual keywords sequel keywords order by. contentResolver will then execute our 135 00:09:52,750 --> 00:09:56,240 query against its data source and give us back a cursor. 136 00:09:56,440 --> 00:09:59,000 We can then use the cursor just like we did earlier. 137 00:09:59,200 --> 00:10:05,200 We'll just use a loop to loop through all the rows in the cursor and display the contact names. So that 138 00:10:05,200 --> 00:10:05,920 bit's easy. 139 00:10:06,010 --> 00:10:08,380 But what's the contentResolver all about. 140 00:10:08,680 --> 00:10:13,100 Well I said that there were several levels of redirection here, and we'll look at that in the next video.