1
00:00:05,290 --> 00:00:11,570
Welcome back. Okay, we finished the
last video by looking at the text that

2
00:00:11,570 --> 00:00:16,910
we've hard-coded into the app. We should
put the text into string resources, just

3
00:00:16,910 --> 00:00:22,250
like we do for layouts.  I'll start with
the name TextView that displays the

4
00:00:22,250 --> 00:00:30,290
heading. Click on the word "instructions"
and expand the drop-down that appears, on

5
00:00:30,290 --> 00:00:38,090
the left hand side. We want Extract
String Resource from the menu, and we'll

6
00:00:38,090 --> 00:00:52,070
call this instructions_heading. Click OK and Android studio

7
00:00:52,070 --> 00:00:58,039
replaces the text with a string resource.
Unfortunately it doesn't do a perfect

8
00:00:58,039 --> 00:01:04,519
job, and we've got an error. This is
because we don't have a context readily

9
00:01:04,519 --> 00:01:12,530
available, to call the getstring function
on. As it happens, we don't need one. The

10
00:01:12,530 --> 00:01:18,200
setText function will accept a string
resource ID instead. We can delete the

11
00:01:18,200 --> 00:01:24,380
call to context.getString, and the
extra parentheses, to get rid of the

12
00:01:24,380 --> 00:01:36,039
error. Do the same thing in description.
This time call the resource instructions.

13
00:01:37,780 --> 00:01:43,820
And that didn't go well. You'll often
find that long strings in code are split

14
00:01:43,820 --> 00:01:49,340
up, like we've done here. But if you're in
the habit of doing that, then it's a good

15
00:01:49,340 --> 00:01:55,009
habit to break, when writing Android apps.
You'll almost always want to extract the

16
00:01:55,009 --> 00:02:00,289
string into a string resource, and that's
much easier if you haven't split the

17
00:02:00,289 --> 00:02:06,969
text up like this.
Ok, I'll undo that change.

18
00:02:10,360 --> 00:02:15,760
Now I need to put all the text back into
a single line, then extract the resource

19
00:02:15,760 --> 00:02:21,070
again. It's a bit fiddly, which is why I
suggest you don't split the text up in

20
00:02:21,070 --> 00:02:28,560
the first place. The light bulb can help
here again. It has an option Convert

21
00:02:28,560 --> 00:02:35,200
Concatenation to Template. That removes
the concatenation, and we should now be

22
00:02:35,200 --> 00:02:41,650
able to use a light bulb again to create
the string resource. I say "should" because

23
00:02:41,650 --> 00:02:47,020
I've been unable to get that option to
appear. It's not because we used the

24
00:02:47,020 --> 00:02:52,060
Convert to Template option either. At the
moment, Android Studio won't provide the

25
00:02:52,060 --> 00:02:57,910
string resource option for this text.
Whether that's because it's too long, or

26
00:02:57,910 --> 00:03:02,920
because it contains line break
characters, I don't know. That might

27
00:03:02,920 --> 00:03:08,890
change in a later version, but for the
moment it doesn't work. As we've said

28
00:03:08,890 --> 00:03:15,400
before, "life's too short to fight the tools".
We know what the option should do

29
00:03:15,400 --> 00:03:21,519
so let's just do it. I'll cut all the
text for the description, without the

30
00:03:21,519 --> 00:03:24,150
quote marks,

31
00:03:30,500 --> 00:03:40,860
then open up the strings.xml file
from resources values. I'll add the new

32
00:03:40,860 --> 00:03:57,090
resource after instructions heading
calling it instructions, and paste the

33
00:03:57,090 --> 00:04:05,190
text. The right-click context menu has a
paste simple option, which will paste the

34
00:04:05,190 --> 00:04:09,870
text in, keeping the \ns
instead of replacing them with line

35
00:04:09,870 --> 00:04:15,330
breaks. While we're here, there's a blank
fragment resource that was created by the

36
00:04:15,330 --> 00:04:21,660
wizard, when we created the add/edit
fragment. We don't need that so it can be

37
00:04:21,660 --> 00:04:26,090
deleted, along with the TODO comment.

38
00:04:28,220 --> 00:04:41,250
Back in the adapter, we use the same name, instructions,
as a resource ID. Okay the

39
00:04:41,250 --> 00:04:52,950
next function we have to implement is
getItemCount. The RecyclerView uses

40
00:04:52,950 --> 00:04:58,139
this so it knows how many items there
are to display. If there are no items,

41
00:04:58,139 --> 00:05:03,570
we'll be sending back a view that
displays the instructions. So we don't

42
00:05:03,570 --> 00:05:08,160
want to tell the RecyclerView that there
are no records, we'll always return at

43
00:05:08,160 --> 00:05:10,760
least one.

44
00:05:16,710 --> 00:05:20,520
we'll log the start

45
00:05:20,760 --> 00:05:27,560
We'll create a variable called cursor of
type Cursor to hold the cursor.

46
00:05:27,560 --> 00:05:34,110
We'll make a count variable which is of
type integer, and if it is either null or

47
00:05:34,110 --> 00:05:39,270
it doesn't have any items in it, in other
words the count is zero, we're going to

48
00:05:39,270 --> 00:05:42,600
return a value of one. This is a bit of a fib

49
00:05:42,600 --> 00:05:46,500
because actually we'll return a single
view holder that's containing the

50
00:05:46,500 --> 00:05:49,880
instructions that we want to show.

51
00:05:50,500 --> 00:06:00,349
Otherwise let's return the count, then
let's log the fact that we've finished,

52
00:06:00,349 --> 00:06:08,090
and actually return the value. That's all
the overridden functions done, but

53
00:06:08,090 --> 00:06:14,949
there's one more function we still need
to add. Google haven't created a basic

54
00:06:14,949 --> 00:06:21,080
CursorRecyclerViewAdapter class, so
we're modifying RecyclerView's Adapter

55
00:06:21,080 --> 00:06:26,990
class. That's what we're extending, to
produce this class. But the adapter

56
00:06:26,990 --> 00:06:32,300
doesn't know about cursors, so it doesn't
have functions to deal with them. The

57
00:06:32,300 --> 00:06:39,680
CursorAdapter class has one additional
function, and that's swapCursor. We're

58
00:06:39,680 --> 00:06:43,699
implementing the functionality of a
CursorAdapter that's tailored for a

59
00:06:43,699 --> 00:06:50,539
RecyclerView, so it makes sense to use
the same name for our function. We'll add

60
00:06:50,539 --> 00:06:57,830
it after the getItemCount function, and
then discuss what it's doing. We'll

61
00:06:57,830 --> 00:07:02,030
comment our function, to help others that
look at our code, and to help our future

62
00:07:02,030 --> 00:07:04,659
selves.

63
00:07:20,710 --> 00:07:27,970
We'll define our function to take a new
cursor and return a cursor. If the old

64
00:07:27,970 --> 00:07:32,949
cursor and the new cursor are the same,
then we're not really doing a swap and so

65
00:07:32,949 --> 00:07:44,009
we'll return null. We'll save the current
itemCount, and we'll save our old cursor.

66
00:07:45,000 --> 00:07:54,190
We'll create our new cursor, and if that
new cursor isn't null then we'll notify

67
00:07:54,190 --> 00:07:57,930
the observers about the new cursor.

68
00:08:00,630 --> 00:08:07,720
Otherwise we'll remove all the items, and
notify the observers that that has

69
00:08:07,720 --> 00:08:14,710
happened. Finally, we'll return the cursor
as promised. This basically allows the

70
00:08:14,710 --> 00:08:19,389
adaptors cursor to be swapped, when the
underlying data changes and has to be

71
00:08:19,389 --> 00:08:26,410
requeried. This is boilerplate code. You'll
find examples like this a lot online. It

72
00:08:26,410 --> 00:08:31,349
should be called whenever the cursor
that the adapters using is changed.

73
00:08:31,349 --> 00:08:36,909
We'll see it being used in MainActivityFragment,
when we provide a valid cursor

74
00:08:36,909 --> 00:08:41,799
for the first time, and then whenever the
data changes. This function returns the

75
00:08:41,799 --> 00:08:46,330
previous cursor, which can be useful if
the owner of the cursor needs to close

76
00:08:46,330 --> 00:08:52,420
it. In code that uses a CursorLoader, we
didn't have to worry about this because

77
00:08:52,420 --> 00:08:57,880
the CursorLoader class takes care of it.
But that's how the CursorAdapter does

78
00:08:57,880 --> 00:09:02,230
things, and I've stuck with the standard
code so that it can be used with a

79
00:09:02,230 --> 00:09:08,980
custom Loader if needed. As it turns out,
we do need to close the old cursor; and

80
00:09:08,980 --> 00:09:13,990
now that the Loader classes have been
deprecated, we lose the functionality

81
00:09:13,990 --> 00:09:19,830
that they provide. The Loader took care
of things like closing old cursors, and

82
00:09:19,830 --> 00:09:24,990
also made sure that database queries
were executed on a background thread.

83
00:09:24,990 --> 00:09:29,890
Don't feel too bad that you can't use
them though, they were a bit cumbersome

84
00:09:29,890 --> 00:09:34,150
to set up, and things aren't any harder
now that we can't use them.

85
00:09:34,150 --> 00:09:39,430
in fact I think things are a bit easier now,
as you'll see when we come to create

86
00:09:39,430 --> 00:09:45,730
our ViewModel. But I'm getting ahead of
myself, back to our code. I'll be

87
00:09:45,730 --> 00:09:51,070
discussing these 2 notify functions
later. Remember we still have to make a

88
00:09:51,070 --> 00:09:55,540
change to our ContentProvider, so the
RecyclerView shows updates to the

89
00:09:55,540 --> 00:10:03,040
database. Basically, what these calls do
is notify any observer - such as the

90
00:10:03,040 --> 00:10:08,530
RecyclerView - that the data from this
adapter has changed. If the new cursor

91
00:10:08,530 --> 00:10:15,220
isn't null, then we use notifyDataSetChanged
but if it is null then we pass the entire

92
00:10:15,220 --> 00:10:21,910
range of records - that's 0 up to the
value of getItemCount - when we call

93
00:10:21,910 --> 00:10:28,060
notifyItemRangeRemoved. This signals
that the entire range of records has

94
00:10:28,060 --> 00:10:34,990
gone. And that's our adapter finished, for
now anyway. We've still got to deal with

95
00:10:34,990 --> 00:10:38,860
the buttons being tapped, but we'll come
back to that once we've got the RecyclerView

96
00:10:38,860 --> 00:10:43,090
working. To get it working, we just
have to link it up to this adapter, in

97
00:10:43,090 --> 00:10:46,600
MainActivityFragment.

98
00:10:51,220 --> 00:10:53,340
We'll have to refer to the adapter in several

99
00:10:53,340 --> 00:10:59,060
places in code, so I'll start by declaring a
field to store it.

100
00:10:59,060 --> 00:11:04,670
We passed null as the cursor, because we
don't have one that's available yet.

101
00:11:04,670 --> 00:11:10,780
Passing null will cause the adapter to
return a view containing our instructions,

102
00:11:10,860 --> 00:11:14,780
and that's exactly what we want to happen,
when the app starts with

103
00:11:14,780 --> 00:11:19,940
no task records. I'll add the code to
attach the adapter to the RecyclerView

104
00:11:19,940 --> 00:11:28,420
in onViewCreated.

105
00:11:28,420 --> 00:11:32,900
Let's set our LayoutManager to a LinearLayoutManager and

106
00:11:32,900 --> 00:11:40,140
attach the adapter. We gave our RecyclerView the ID task_list and

107
00:11:40,140 --> 00:11:46,110
we're referring to it using the
synthetic import. You won't see any data

108
00:11:46,110 --> 00:11:51,180
yet, but we can run the app and make sure
we haven't broken anything. If all goes

109
00:11:51,180 --> 00:11:56,030
well, we should see the instructions
displayed.

110
00:12:03,790 --> 00:12:09,280
okay I'll stop this video here. In the
next video we'll write the ViewModel

111
00:12:09,280 --> 00:12:16,770
class that will populate our adapter's
cursor. See you in the next video.

