1 00:00:04,400 --> 00:00:06,420 G'day everyone, welcome back. 2 00:00:06,420 --> 00:00:11,820 To finish moving our save code from AddEditFragment to TaskTimerViewModel 3 00:00:11,820 --> 00:00:15,080 we need to write the saveTask function in the ViewModel. 4 00:00:15,080 --> 00:00:25,980 I'll put it before the deleteTask function, because it seems more logical to have save before delete. 5 00:00:25,980 --> 00:00:35,160 So let's define our function, give ourselves somewhere to store our information, 6 00:00:35,160 --> 00:00:44,280 and implement a little bit of business logic. Remember, if the task name is empty we don't save. 7 00:00:44,280 --> 00:00:54,360 If it's not empty, let's collect up the values from the interface. 8 00:00:54,360 --> 00:00:59,180 Now, if the task id is zero it means we have a new task. 9 00:00:59,180 --> 00:01:07,840 In which case, we need to add the new task. 10 00:01:07,840 --> 00:01:13,080 We'll make sure that we've got a valid URI, or at least, one that isn't null, 11 00:01:13,080 --> 00:01:17,220 and then we'll assign it an ID 12 00:01:17,220 --> 00:01:22,980 and of course, we log all of that just so we can track what's going on. 13 00:01:22,980 --> 00:01:30,460 If we do have an existing task, in other words, the ID was not equal to zero, 14 00:01:30,460 --> 00:01:39,240 then, once more, we just need to log 15 00:01:39,240 --> 00:01:44,100 and update our task. 16 00:01:44,100 --> 00:01:47,560 All of that's quite similar to the code we had in the fragment, 17 00:01:47,560 --> 00:01:52,600 simplified because we're not comparing the widgets to the original task. 18 00:01:52,600 --> 00:01:56,620 To decide whether we're saving a new task or updating an existing one, 19 00:01:56,620 --> 00:02:04,260 we check the ID. If the ID's zero, then the task didn't come from the database and must be a new task. 20 00:02:04,260 --> 00:02:09,720 The logic to prevent a task being saved, if it's name is blank, also appears here. 21 00:02:09,720 --> 00:02:15,040 That's the business logic, and it belongs in the modelled layer not the UI layer. 22 00:02:15,040 --> 00:02:18,200 We need to test that the URI isn't null. 23 00:02:18,200 --> 00:02:25,520 That's what we do on line 73, because the ContentResolver's insert function can return null. 24 00:02:25,520 --> 00:02:30,160 Although we're using Kotlin, we can't escape from null checks completely, 25 00:02:30,160 --> 00:02:32,900 not as long as we're using Java classes. 26 00:02:32,900 --> 00:02:37,460 One thing that may not be obvious, is why we're returning the task. 27 00:02:37,460 --> 00:02:41,340 We got it from the calling code, so why send it back? 28 00:02:41,340 --> 00:02:46,260 The reason is, that it may now have an ID that it didn't have before. 29 00:02:46,260 --> 00:02:52,940 Let's have a quick look at the saveTask function in AddEditFragment. 30 00:02:52,940 --> 00:02:57,480 That's got a Task instance, which may be null for a new task. 31 00:02:57,480 --> 00:03:03,900 Now, at the moment, we've written the app so that the fragment is removed when we save the task. 32 00:03:03,900 --> 00:03:10,060 You may decide not to do that. The app may allow the user to keep making changes, and saving them. 33 00:03:10,060 --> 00:03:15,860 In that case, the fragment's Task instance should reflect the data in the database. 34 00:03:15,860 --> 00:03:22,460 Otherwise, we could keep creating new tasks when we save, instead of updating the one that now exists. 35 00:03:22,460 --> 00:03:31,180 That's why we assign the result of calling ViewModel's saveTask function, back to the task. 36 00:03:31,180 --> 00:03:44,220 Okay, that's the function added. Let's see if it works. 37 00:03:44,220 --> 00:03:53,240 We're upto task 8, so tap the plus icon in the toolbar and enter task 8 for the name, 38 00:03:53,240 --> 00:03:59,240 8th task for the description, and save. 39 00:03:59,240 --> 00:04:00,960 That's looking good. 40 00:04:00,960 --> 00:04:14,560 How about editing an existing task. I'll edit task 10, and change 1st in its description, to first. 41 00:04:14,560 --> 00:04:19,940 Tap save again, and the entry's updated. 42 00:04:19,940 --> 00:04:21,459 Our change works. 43 00:04:21,459 --> 00:04:23,340 At the end of the last video, 44 00:04:23,340 --> 00:04:28,800 I asked you to think about whether the list in MainActivityFragment would be updated, 45 00:04:28,800 --> 00:04:33,020 if both fragments are using their own instance of the ViewModel. 46 00:04:33,020 --> 00:04:38,440 Clearly it does get updated, so here's a mini challenge. 47 00:04:38,440 --> 00:04:49,300 How is MainActivityFragment receiving a new cursor, if it uses a different ViewModel instance to AddEditFragment? 48 00:04:49,300 --> 00:04:52,180 And here's the answer. The reason it works, 49 00:04:52,180 --> 00:04:58,900 is that both ViewModel instances are receiving notifications from a single ContentResolver. 50 00:04:58,900 --> 00:05:04,060 There is only one ContentResolver and it belongs to the application. 51 00:05:04,060 --> 00:05:08,520 It doesn't matter which instance of the ViewModel makes a change to the data, 52 00:05:08,520 --> 00:05:13,880 the ContentResolver will notify all its observers about that change. 53 00:05:13,880 --> 00:05:18,760 In the next video, we'll go through some slides to explain how all this is working. 54 00:05:18,760 --> 00:05:21,240 See you then.