1 00:00:04,980 --> 00:00:07,500 G'day everyone, welcome back. 2 00:00:07,500 --> 00:00:11,140 In the last video we got our cursor adapter working. 3 00:00:11,140 --> 00:00:14,740 Well we think it's working. We know it hasn't broken anything 4 00:00:14,740 --> 00:00:17,720 and that it works fine when there is no data, 5 00:00:17,720 --> 00:00:24,460 but we can't test it further until we've created the view model class that's going to provide it with data. 6 00:00:24,460 --> 00:00:26,520 So let's get started. 7 00:00:26,520 --> 00:00:36,580 Right click on the project and choose New Kotlin File/Class. 8 00:00:36,580 --> 00:00:45,540 I'll call it TaskTimerViewModel 9 00:00:45,540 --> 00:00:50,040 and select class from the drop-down. 10 00:00:50,040 --> 00:00:53,960 We saw how view models worked in the previous section. 11 00:00:53,960 --> 00:00:56,840 This one's going to be a slight variation. 12 00:00:56,840 --> 00:01:02,980 Instead of extending the ViewModel class we'll extend an Android view model. 13 00:01:02,980 --> 00:01:08,960 Both classes work the same way. AndroidViewModel is a subclass of ViewModel, 14 00:01:08,960 --> 00:01:11,760 but it also has an application property. 15 00:01:11,760 --> 00:01:15,660 That's going to be useful if we want to access the database, 16 00:01:15,660 --> 00:01:20,420 because we'll need an application to get a ContentResolver. 17 00:01:20,420 --> 00:01:31,440 So let's complete our TaskTimerViewModel declaration. 18 00:01:31,440 --> 00:01:39,640 Additionally, of course, let's put a tag in to help with our logging. 19 00:01:39,640 --> 00:01:45,300 It's worth control clicking on the AndroidViewModel to check out the source code. 20 00:01:45,300 --> 00:01:49,360 That's command click on a Mac. 21 00:01:49,360 --> 00:01:52,140 Once again, this is Java code. 22 00:01:52,140 --> 00:01:57,460 So it's slightly more verbose than Kotlin but it's easy enough to understand. 23 00:01:57,460 --> 00:02:01,980 AndroidViewModel is a subclass of ViewModel. 24 00:02:01,980 --> 00:02:07,600 The Java keyword, extends, is used to specify the superclass. 25 00:02:07,600 --> 00:02:10,880 As we said, it has an application property. 26 00:02:10,880 --> 00:02:17,080 The application property is set in the constructor, which is a separate method in Java. 27 00:02:17,080 --> 00:02:23,660 You can write constructors that way in Kotlin, but it's more convenient to just use the primary constructor, 28 00:02:23,660 --> 00:02:27,300 and list the properties when defining the class. 29 00:02:27,300 --> 00:02:34,360 Being Java, it also has a getter for the application, the getApplication function. 30 00:02:34,360 --> 00:02:37,260 This complicates our Kotlin code slightly 31 00:02:37,260 --> 00:02:42,820 because it allows the application argument to also be a subclass of application. 32 00:02:42,820 --> 00:02:46,660 That's what the T extends Application means. 33 00:02:46,660 --> 00:02:52,840 It can return any type as long as that type is an Application, or a subclass of it. 34 00:02:52,840 --> 00:02:57,100 You'll see the slight complication that this causes us, shortly. 35 00:02:57,100 --> 00:03:00,900 Ok, back to our ViewModel. 36 00:03:00,900 --> 00:03:06,120 We want it to make a cursor available via a LiveData object. 37 00:03:06,120 --> 00:03:11,880 We've seen that before. When the cursor changes, observers will be notified of that change. 38 00:03:11,880 --> 00:03:16,460 In this case, the observer will be MainActivityFragment. 39 00:03:16,460 --> 00:03:22,660 When it gets notified of a change, it'll swap the cursor in the RecyclerviewAdapter. 40 00:03:22,660 --> 00:03:34,600 We'll make our database cursor a private variable of type MutableLiveData. 41 00:03:34,600 --> 00:03:40,700 We'll define our cursor as a LiveData cursor 42 00:03:40,700 --> 00:03:45,340 and we'll return the database cursor in the get method. 43 00:03:45,340 --> 00:03:53,100 Our ViewModel will load the data from the database then update the database cursor LiveData object. 44 00:03:53,100 --> 00:03:56,000 We'll add that code in a separate function. 45 00:03:56,000 --> 00:04:00,760 We'll define our load tasks method. 46 00:04:00,760 --> 00:04:16,320 Our projection array will define the data table's columns. 47 00:04:16,320 --> 00:04:22,340 We'll put a comment in to remind us of what we're doing, 48 00:04:22,340 --> 00:04:30,120 and we'll define our sort order. 49 00:04:30,120 --> 00:04:48,000 Then we'll define our cursor using to projection array and the sort order. 50 00:04:48,000 --> 00:04:51,880 Then we'll set the database cursor value. 51 00:04:51,880 --> 00:04:56,140 That's the standard code for fetching data from the ContentProvider. 52 00:04:56,140 --> 00:05:03,100 What might look a bit strange is the way we have to get the ContentResolver on line 25. 53 00:05:03,100 --> 00:05:09,220 As we're using Kotlin you may expect that we could refer to the application property directly, 54 00:05:09,220 --> 00:05:12,360 rather than calling the Java getter method. 55 00:05:12,360 --> 00:05:15,500 That's the slight complication I mentioned before. 56 00:05:15,500 --> 00:05:20,960 Because we have to specify the exact type of application inside the diamond operator, 57 00:05:20,960 --> 00:05:23,400 we must use the getter. 58 00:05:23,400 --> 00:05:29,060 It's a minor inconvenience, but does make the AndroidViewModel class more flexible, 59 00:05:29,060 --> 00:05:31,440 and it does it in a type-safe way. 60 00:05:31,440 --> 00:05:36,080 If you want to store the application parameter that was passed via the constructor, 61 00:05:36,080 --> 00:05:38,920 then you could create a property to store it. 62 00:05:38,920 --> 00:05:43,100 That would work, but I wanted to show you this strange syntax. 63 00:05:43,100 --> 00:05:45,640 I've also jumped the gun a bit here. 64 00:05:45,640 --> 00:05:52,620 On line 30, I've called the postValue function to set up our database cursor's value. 65 00:05:52,620 --> 00:05:56,960 This is instead of assigning it directly to its value property. 66 00:05:56,960 --> 00:05:59,880 You may remember, back in the previous section, 67 00:05:59,880 --> 00:06:04,100 that postValue was used when you're updating the value on a different thread 68 00:06:04,100 --> 00:06:08,040 to the one that the MutableLiveData object was created on. 69 00:06:08,040 --> 00:06:10,960 I won't say any more about that just yet 70 00:06:10,960 --> 00:06:15,100 because I'll be giving away the answer to a mini-challenge if I do. 71 00:06:15,100 --> 00:06:19,860 Ignore the warning about closing the cursor, if you get one on line 30. 72 00:06:19,860 --> 00:06:24,720 The warning's correct, it is our responsibility to close the cursor. 73 00:06:24,720 --> 00:06:32,280 We can't do that now though. If we do, it will be invalid when the adapter tries to get the data from it. 74 00:06:32,280 --> 00:06:36,940 I mentioned that briefly when we wrote the swap cursor function in our adapter. 75 00:06:36,940 --> 00:06:39,280 This is what I was referring to. 76 00:06:39,280 --> 00:06:43,480 The adapter doesn't own the cursor, so it shouldn't close it. 77 00:06:43,480 --> 00:06:47,860 We'll see how to deal with this when we've finished writing all the code. 78 00:06:47,860 --> 00:06:50,560 All right, we're just about done. 79 00:06:50,560 --> 00:06:55,000 All that remains is to call that loadTasks function. 80 00:06:55,000 --> 00:07:01,320 We can do that in an init block, which will be executed when the ViewModel instance gets created. 81 00:07:01,320 --> 00:07:15,220 I like to put init code at the start of the class, after the property and the variable declarations. 82 00:07:15,220 --> 00:07:19,692 We'll make sure that we log the start 83 00:07:19,700 --> 00:07:24,460 and then call our load tasks function. 84 00:07:24,460 --> 00:07:29,780 In the next video we'll subscribe to the ViewModel and see it working. 85 00:07:29,780 --> 00:07:32,700 See you in the next one