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.

