1
00:00:04,780 --> 00:00:07,060
G'day everyone, welcome back.

2
00:00:07,060 --> 00:00:12,360
At the end of the last video,
we were able to add new tasks the database,

3
00:00:12,360 --> 00:00:16,059
but the RecyclerView wasn't updating to display them.

4
00:00:16,059 --> 00:00:20,140
We had to close the app and run it again to see the new tasks.

5
00:00:20,140 --> 00:00:23,700
That's not exactly the ideal user experience.

6
00:00:23,700 --> 00:00:30,660
Fortunately, all the support to make the RecyclerView
update is built into the Android framework.

7
00:00:30,660 --> 00:00:35,900
So the changes we need to make to our
ContentProvider are really simple.

8
00:00:35,900 --> 00:00:43,800
Where it gets a bit more complex is getting the ViewModel to react
to the notifications that the ContentProvider will issue.

9
00:00:43,800 --> 00:00:47,640
With the CursorLoader all this was handled for us.

10
00:00:47,640 --> 00:00:50,240
Now we have to do it ourselves.

11
00:00:50,240 --> 00:00:57,100
One thing you may be asking is, why does he keep talking about loaders when they've been deprecated.

12
00:00:57,100 --> 00:00:58,760
The answer is simple.

13
00:00:58,760 --> 00:01:05,860
If loaders are deprecated, they're going to be removed from Android at some point over the next couple of years.

14
00:01:05,860 --> 00:01:07,840
But before that happens,

15
00:01:07,840 --> 00:01:10,540
companies that have apps that used loaders

16
00:01:10,540 --> 00:01:16,260
are going to be looking for programmers that
can make them work without the loaders.

17
00:01:16,260 --> 00:01:21,180
After completing this section, you'll be one of those programmers.

18
00:01:21,180 --> 00:01:28,460
Okay there are two parts to this.
The first step is something that I've hinted at a few times.

19
00:01:28,460 --> 00:01:35,580
We need to modify our ContentProvider, so that it notifies any observers about changes to the data.

20
00:01:35,580 --> 00:01:41,380
Our ContentProvider has three functions
that can result in changes to the data;

21
00:01:41,380 --> 00:01:45,100
the insert, update and delete functions.

22
00:01:45,100 --> 00:01:52,520
The code we need to add is very similar for all three, so let's start with the insert function in the AppProvider.

23
00:01:52,520 --> 00:02:01,780
Open our AppProvider, scroll down a bit, and the change is simple.

24
00:02:01,780 --> 00:02:09,160
If something was inserted then
the record ID will be non-zero.

25
00:02:09,160 --> 00:02:12,860
Let's log that we're starting,

26
00:02:12,860 --> 00:02:17,240
and then we'll call the notifyChange function

27
00:02:17,240 --> 00:02:20,560
with the URI of the value that has changed.

28
00:02:20,560 --> 00:02:25,340
Notice that we're passing the original URI that was provided to the insert function.

29
00:02:25,340 --> 00:02:30,220
The URI that the function returns
will have the new ID appended to it

30
00:02:30,220 --> 00:02:33,640
and that refers to a specific row in the table.

31
00:02:33,640 --> 00:02:38,680
It is the URI for the entire table that we want to notify changes on.

32
00:02:38,680 --> 00:02:44,440
I used the safe call operator when getting the
ContentResolver from the context.

33
00:02:44,440 --> 00:02:50,500
We know the context won't be null,
but using the safe call operator removes warnings.

34
00:02:50,500 --> 00:02:53,880
We do something very similar for the update function.

35
00:02:53,880 --> 00:03:05,100
Scroll down a little way further, and once again
check that the count is greater than zero.

36
00:03:05,100 --> 00:03:07,800
That makes sure something happened.

37
00:03:07,800 --> 00:03:15,900
Log that we've started, and then call the
ContextResolver to notify the change,

38
00:03:15,900 --> 00:03:19,120
again, passing the URI.

39
00:03:19,120 --> 00:03:22,100
The final change is to the delete function.

40
00:03:22,100 --> 00:03:40,640
Once again, it's pretty much the same.

41
00:03:40,640 --> 00:03:43,020
That's the first part done.

42
00:03:43,020 --> 00:03:48,320
When we call a function of the ContentProvider
that results in a change to the database,

43
00:03:48,320 --> 00:03:53,400
the ContentResolver will notify any observers about the change.

44
00:03:53,400 --> 00:03:56,620
The second part is to observe these notifications.

45
00:03:56,620 --> 00:04:00,740
We do that in the TaskTimerViewModel class.

46
00:04:00,740 --> 00:04:08,400
We need to create a ContentObserver and register it.
Let's start by creating a ContentObserver.

47
00:04:08,400 --> 00:04:30,540
If you're prompted for the correct import in the handler, we want android.os.handler.

48
00:04:30,540 --> 00:04:35,160
When a change is notified, the onChange function will be called.

49
00:04:35,160 --> 00:04:42,620
We log the fact, then we call loadTasks to reload the data, and update the current cursor LiveData.

50
00:04:42,620 --> 00:05:01,240
The next step is to register the observer,
and the init code is a good place to do that.

51
00:05:01,240 --> 00:05:05,180
We tell it the URI that we want to observe changes on

52
00:05:05,180 --> 00:05:08,660
and provide our ContentObserver.

53
00:05:08,660 --> 00:05:14,780
In an app with many tables that get updated,
we can create an observer for each URI,

54
00:05:14,780 --> 00:05:20,280
or we could register the same observer for several URIs.

55
00:05:20,280 --> 00:05:26,400
Notice that the URI is passed into the
onChange function on line 22,

56
00:05:26,400 --> 00:05:30,040
so we could respond differently to different URIs.

57
00:05:30,040 --> 00:05:35,420
When you register an observer like this,
it's important to unregister it again.

58
00:05:35,420 --> 00:05:39,120
If you don't, you can end up with memory leaks.

59
00:05:39,120 --> 00:05:44,540
Remember from our discussion on ViewModels,
that they have an onCleared function.

60
00:05:44,540 --> 00:05:50,400
That function gets called when the ViewModel's no longer used and can be destroyed.

61
00:05:50,400 --> 00:05:56,520
It's a good place to clear up any resources,
and that's where we'll unregister our observer.

62
00:05:56,520 --> 00:06:06,060
Android studio will generate the stub for us.

63
00:06:06,060 --> 00:06:11,760
ctrl o, select onCleared

64
00:06:11,760 --> 00:06:19,900
remove what's already there, and add our code.

65
00:06:19,900 --> 00:06:23,640
Unregistering the observer is similar to registering it.

66
00:06:23,640 --> 00:06:28,840
We call the ContentResolver's
unregisterContentObserver function.

67
00:06:28,840 --> 00:06:37,980
Let's see that running

68
00:06:37,980 --> 00:06:50,820
We should be up to task 7

69
00:06:50,820 --> 00:06:53,620
but we'll set the sort order to 2.

70
00:06:53,620 --> 00:06:57,740
That way it should appear on the list before task 6.

71
00:06:57,740 --> 00:07:06,140
I'll click Save, and when I return to the main screen
there's our new task 7 showing in the list.

72
00:07:06,140 --> 00:07:08,100
Let's have a look in the logcat,

73
00:07:08,100 --> 00:07:12,820
and also see how to fix a quirk that it's got at the moment.

74
00:07:12,820 --> 00:07:17,960
If you find your log cat running wild and logging all sorts of things,

75
00:07:17,960 --> 00:07:23,060
even when you've got the show only selected application
filter on the right,

76
00:07:23,060 --> 00:07:24,540
don't panic.

77
00:07:24,540 --> 00:07:32,340
Use the second drop down from the left
and select your application again.

78
00:07:32,340 --> 00:07:38,860
That causes it to respect the filter.
It seems to be a quirk in Android Studio at the moment.

79
00:07:38,860 --> 00:07:51,240
Ok, type the filter, query|insert, with the regex box checked.

80
00:07:51,240 --> 00:07:54,300
That will make it easier to find what we want.

81
00:07:54,300 --> 00:07:59,440
There's our insert happening, and just below that
we can see the query being called.

82
00:07:59,440 --> 00:08:04,560
So our ViewModel has re-queried the database
to refresh its cursor.

83
00:08:04,560 --> 00:08:12,880
It then updates the database cursor MutableLiveData object,
which is being observed by the MainActivityFragment.

84
00:08:12,880 --> 00:08:16,980
When the MainActivityFragment observes that the cursor has changed,

85
00:08:16,980 --> 00:08:22,820
it swaps the adapter's cursor and the RecyclerView can immediately access the new data.

86
00:08:22,820 --> 00:08:26,800
There are two important changes we had to make,
to make all that happen.

87
00:08:26,800 --> 00:08:34,240
Firstly, we made sure that all our functions that can change the database; insert, delete and update,

88
00:08:34,240 --> 00:08:35,780
in the AppProvider,

89
00:08:35,780 --> 00:08:40,059
call the ContentResolver's notifyChange function.

90
00:08:40,059 --> 00:08:44,620
And so they notify the listeners that
there's been a change.

91
00:08:44,620 --> 00:08:48,980
Then, we set up a ContentObserver in the ViewModel class,

92
00:08:48,980 --> 00:08:52,080
and registered it to be notified of the changes.

93
00:08:52,080 --> 00:08:54,940
Okay, we'll stop the video there.

94
00:08:54,940 --> 00:08:59,460
In the next video, we'll work on the onClick listeners for the buttons,

95
00:08:59,460 --> 00:09:03,000
so that we can then edit and delete tasks.

96
00:09:03,000 --> 00:09:08,180
By the time we've done that, you should be able to tell me what we're doing wrong.

97
00:09:08,180 --> 00:09:12,760
Our code works, but we're doing something that we really shouldn't be doing.

98
00:09:12,760 --> 00:09:15,980
It's something we've seen mentioned in the documentation,

99
00:09:15,980 --> 00:09:18,200
and we've hinted at it a couple of times.

100
00:09:18,200 --> 00:09:24,520
We'll be putting it right in a future video, but until then,
see if you can work out what it is.

101
00:09:24,520 --> 00:09:27,500
See you in the next video

