G'day everyone, welcome back.
In this video, we're going to remove the dependency that our AddEditFragment has on the content resolver.
Instead of saving the task details, it will just pass them on to TaskTimerViewModel,
and the ViewModel will take care of saving them.
We've got a small optimisation in AddEditFragment's code to save the task details.
It's described in the comment at the start of the saveTask function.
We'll only save the details if something has changed.
That's not business logic, and I'm going to leave that test in the fragment.
If you're not sure whether something counts as business logic, and therefore whether it belongs in the model,
ask the question, Would the program still give the same results without it?
Here, the program would still do the same thing if we saved the data, regardless of whether it had changed or not.
It would be less efficient, obviously, but the results would be the same.
We have got a bit of business logic in here. The code checks to see if the task name isn't empty.
That's not something the UI should be concerned with, so that test will be moved to the ViewModel.
I'm also going to reverse the decision that we made earlier.
When we looked at Kotlin data classes, we decided not to make Task a data class.
That decision was made before Google deprecated the Loader classes.
While changing the code from using a Loader to using a ViewModel,
it became clear that a data class would provide some benefit.
The important benefit we'll get, is the ability to compare two Task objects, so I'm going to make my Task a data class.
You'll see why in a moment.
While we're here, we've got a warning that id won't be serialized into a parcel.
That was fine, but now we're going to need it to be.
The fix is to move it into the primary constructor,
and this time I'll accept Android Studio's suggestion, and remove the empty class body.
Just to be clear, I've made those changes because the app was originally written to use a Loader.
Google's decision to deprecate the Loader classes came as a bit of a surprise,
and we've modified the app to use a ViewModel instead.
By using a data class, we can make our next bit of code simpler.
Okay, time to make some changes to AddEditFragment.
At the moment the saveTask function is using values from the EditText widgets in the layout.
Our ViewModel has no knowledge of those widgets, and we're going to pass it a Task object instead.
Later in the course, you'll see another place where we need to create a new task from the contents of the EditText widgets.
To save time later, I'm going to create a new function to do that.
I'll call it task from UI, and add it before the saveTask function.
We'll define the function, we'll get value for sortOrder.
If it's not empty, then we're going to return the values that already exist by parsing it from the string,
Otherwise, we'll return a zero, we'll make our new task, assign it an ID, and then return it.
As we said, if there's a value in the sortOrder widget, we'll convert it to an integer.
Otherwise, we'll set it to zero.
When we create the new task, we'll use the contents of the EditText widgets for its properties.
If we were editing an existing task, we also store the existing task ID.
I used the Elvis operator on line 73, to assign the value 0 if the fragment's task is null.
In other words, if we're adding a new task.
That removes a lot of code from saveTask.
In fact, it's now easier to delete the entire contents of saveTask and start again, rather than trying to change it.
Let's define the function.
We'll add a comment so that we remember what this is for.
We'll create our new Task object, and we'll get the values from our EditText widgets.
Then we'll check to see if it's the same task that we were given, when the fragment was created.
The tasks we're editing, in other words.
If they're not the same, then at least one thing has changed,
and we'll call the saveTask function in the ViewModel.
We haven't written that yet but we'll do that next.
This is why I made the task a data class.
We can compare two task instances, because a data class provides an equals function for us.
We've got a suggestion the dot equals can be replaced with the binary operator.
Use a light bulb to accept the suggestion.
If you're used to Java, that may horrify you.
Don't worry. Using the equals equals and the not equals operators with data classes works fine, in Kotlin.
Our AddEditFragment doesn't have a ViewModel, so we'd better give it one.
I've declared that slightly differently to the way it's declared in MainActivityFragment.
The difference is subtle but important, and it's a good point to explain it.
To see the difference, I'll copy the declaration from MainActivityFragment, and paste it below this one.
Okay, the difference is in what we're passing as the scope.
In MainActivityFragment we pass the fragment's activity.
Here, we're passing the fragment.
In this app, our fragments don't communicate with each other.
They're totally independent, and aren't observing the same LiveData objects in the ViewModel.
Sometimes, you will want fragments to share some data.
In that case, you can pass the activity as the scope.
Both fragments will then be observing data in the same ViewModel instance,
and that ViewModel will exist as long as the activity does, surviving configuration changes too.
You can find more information about this, here.
The code samples have been converted to Kotlin. They're no longer just in Java.
Unfortunately, there's an error in the Kotlin code at the moment.
On the Java tab, for the example,
both the master fragment and the detail fragment are passing the activity,
and the document refers to that.
At the moment, in the Kotlin code, and I'll click the Kotlin tab, it is this that is being passed in to both fragments.
When you're reading through this, the text only makes sense if activity is passed as the scope there.
So hopefully, by the time you watch this, they'll have corrected the documentation.
I'll go through all this with some slides soon. It's worth reading through this document, after watching that video.
Now, I've said that our fragments don't communicate with each other, and that's true.
However, AddEditFragment's going to update the database via the ViewModel
When that happens, the ViewModel will provide changes to the MainActivityFragment.
Will that work, if the two fragments aren't sharing the same ViewModel instance?
If you get the right answer to that question, then you obviously understand how all this fits together.
Don't worry if you got the wrong answer. We've got some diagrams coming up that will explain how it all works.
I think it's worth demonstrating, rather than just telling you the answer.
I'll delete the declaration that I've just pasted in,
and we'll leave AddEditFragment observing its own ViewModel, just to see what happens.
Okay. I'll stop the video there. In the next video, we'll add the saveTask function to the view model,
and test the changes, and we'll fix the error that we've got in the saveTask function.
See you in the next one.