1 00:00:00,019 --> 00:00:02,422 (gentle, futuristic music) 2 00:00:02,422 --> 00:00:05,620 (keyboard typing) 3 00:00:05,620 --> 00:00:06,453 Right, so we've got 4 00:00:06,453 --> 00:00:08,490 the user interface working well now, 5 00:00:08,490 --> 00:00:11,510 so it's time to get our app to save the data. 6 00:00:11,510 --> 00:00:13,940 In the life cycle videos, I mentioned that you may 7 00:00:13,940 --> 00:00:15,930 prefer to save the data automatically 8 00:00:15,930 --> 00:00:18,420 in the onPause or onStop functions. 9 00:00:18,420 --> 00:00:20,920 That's the decision you make when designing your apps, 10 00:00:20,920 --> 00:00:23,390 and will probably be a good decision for this one. 11 00:00:23,390 --> 00:00:25,940 We're going to use the save button instead. 12 00:00:25,940 --> 00:00:28,900 We're doing that so we can take a look at using dialogues, 13 00:00:28,900 --> 00:00:30,190 which wouldn't be appropriate in 14 00:00:30,190 --> 00:00:32,900 the onPause or onStop functions. 15 00:00:32,900 --> 00:00:34,250 Both of those functions should 16 00:00:34,250 --> 00:00:35,980 finish as quickly as possible, 17 00:00:35,980 --> 00:00:38,040 and popping up a dialogue isn't a good idea 18 00:00:38,040 --> 00:00:40,570 from these life cycle functions. 19 00:00:40,570 --> 00:00:42,380 Interrupting the life cycle while your app 20 00:00:42,380 --> 00:00:45,090 waits for a user to dismiss the dialogue isn't a good thing 21 00:00:45,090 --> 00:00:47,970 to do, in fact, it's a very bad thing to do. 22 00:00:47,970 --> 00:00:49,970 When you've seen the code to save the task data, 23 00:00:49,970 --> 00:00:53,200 then by all means move it into onPause or onStop, 24 00:00:53,200 --> 00:00:56,200 for now we'll put it in the save button's onClickListener, 25 00:00:56,200 --> 00:00:58,790 so that we can cover using dialogues in this app. 26 00:00:58,790 --> 00:01:01,690 Before we can save the details, we need to populate 27 00:01:01,690 --> 00:01:05,010 our edit text widgets with the task details. 28 00:01:05,010 --> 00:01:08,400 Remember that this fragment's being used to add a new task, 29 00:01:08,400 --> 00:01:11,510 as well as edit existing task details. 30 00:01:11,510 --> 00:01:13,770 If the argument passed to the fragment is null, 31 00:01:13,770 --> 00:01:16,860 then we're adding a new task, otherwise the argument 32 00:01:16,860 --> 00:01:19,380 will be the task that we're editing. 33 00:01:19,380 --> 00:01:20,981 I've already mentioned that we can't change 34 00:01:20,981 --> 00:01:23,480 UI elements in the onCreate function, 35 00:01:23,480 --> 00:01:25,860 because our UI doesn't exist at that point. 36 00:01:25,860 --> 00:01:28,123 It's not inflated until onCreateView. 37 00:01:29,100 --> 00:01:31,280 A good place to modify the UI is 38 00:01:31,280 --> 00:01:33,710 in the onViewCreated function. 39 00:01:33,710 --> 00:01:36,760 When that gets called, we know our layout's been inflated, 40 00:01:36,760 --> 00:01:38,660 and all the views exist. 41 00:01:38,660 --> 00:01:41,039 We're already overriding onViewCreate in our 42 00:01:41,039 --> 00:01:43,839 AddEditFragment, and I'll just bring that on the screen. 43 00:01:46,750 --> 00:01:48,200 And we're overriding onViewCreated 44 00:01:48,200 --> 00:01:50,490 so that we could just see it being called. 45 00:01:50,490 --> 00:01:52,230 I could leave it where it is, 46 00:01:52,230 --> 00:01:55,233 and it's right down towards the bottom of the file here. 47 00:01:56,570 --> 00:01:59,500 There it is, onViewCreated, but I prefer to have the life 48 00:01:59,500 --> 00:02:02,720 cycle functions appearing in the order they get called. 49 00:02:02,720 --> 00:02:05,040 All the life cycle functions that we've added 50 00:02:05,040 --> 00:02:07,000 were just there so we could log them, 51 00:02:07,000 --> 00:02:08,460 and we'll leave them still at the 52 00:02:08,460 --> 00:02:10,410 end of the AddEditFragment file, 53 00:02:10,410 --> 00:02:13,770 but I'll move the ones we really want up as we use them. 54 00:02:13,770 --> 00:02:15,080 So for this one, we're going 55 00:02:15,080 --> 00:02:17,340 to cut the onViewCreated function 56 00:02:18,980 --> 00:02:22,640 where it is, and what I'm going to do is paste it 57 00:02:22,640 --> 00:02:26,973 just after the onCreateView function, just here. 58 00:02:30,770 --> 00:02:31,603 Okay. 59 00:02:32,873 --> 00:02:35,060 Right, so in terms of what we want to do here, 60 00:02:35,060 --> 00:02:39,090 if a task exists, we'll set its values into the widgets, 61 00:02:39,090 --> 00:02:41,940 we'll also log what we're doing to make debugging easier. 62 00:02:43,700 --> 00:02:46,570 Right, so in terms of code, we don't need the call to 63 00:02:46,570 --> 00:02:48,920 the super function, so I'm going to delete that line, 64 00:02:48,920 --> 00:02:50,280 but how do I know that? 65 00:02:50,280 --> 00:02:52,453 Well if we CMD or CTRL click that, 66 00:02:55,052 --> 00:02:55,885 and we're checking out the source code, 67 00:02:55,885 --> 00:02:58,620 and as you can see, the function body's empty, 68 00:02:58,620 --> 00:03:00,020 so we know that the super function 69 00:03:00,020 --> 00:03:02,010 is not actually doing anything. 70 00:03:02,010 --> 00:03:05,400 OnViewCreated is called after onCreateView, 71 00:03:05,400 --> 00:03:06,670 but, and this is the interesting bit, 72 00:03:06,670 --> 00:03:09,400 it's called before any save state 73 00:03:09,400 --> 00:03:11,450 has been restored to the view. 74 00:03:11,450 --> 00:03:13,090 That's important, because we're about 75 00:03:13,090 --> 00:03:15,750 to populate the edit text widgets with the 76 00:03:15,750 --> 00:03:18,550 data from the task to be edited. 77 00:03:18,550 --> 00:03:20,820 If the user rotates the device, 78 00:03:20,820 --> 00:03:23,210 these life cycle methods get called again, 79 00:03:23,210 --> 00:03:26,220 and we'll be resetting the widgets to the values they had 80 00:03:26,220 --> 00:03:28,650 when the fragment was first created. 81 00:03:28,650 --> 00:03:31,040 But if we do that after state is restored, 82 00:03:31,040 --> 00:03:33,810 we'd be replacing any edits that the users made. 83 00:03:33,810 --> 00:03:36,050 That wouldn't be good, if all their changes 84 00:03:36,050 --> 00:03:38,980 got wiped out because they rotated their phone. 85 00:03:38,980 --> 00:03:40,710 Because state hasn't been restored yet, 86 00:03:40,710 --> 00:03:42,823 the values we're about to put into the widgets 87 00:03:42,823 --> 00:03:46,460 will be replaced with any text that the users have typed. 88 00:03:46,460 --> 00:03:48,760 So we'll go back to AddEditFragment, 89 00:03:48,760 --> 00:03:51,293 close down this fragment source code. 90 00:03:52,220 --> 00:03:54,260 So we'll actually delete that line and then add the code 91 00:03:54,260 --> 00:03:56,463 and we'll come back to that point shortly. 92 00:03:58,210 --> 00:04:03,200 I can start by typing if task, and task is in parentheses, 93 00:04:03,200 --> 00:04:07,350 is not equal to null, I put a code block, 94 00:04:07,350 --> 00:04:09,800 and then we're going to do a Log.d parentheses 95 00:04:09,800 --> 00:04:11,800 TAG comma, double quotes, onViewCreated, 96 00:04:14,070 --> 00:04:16,882 colon space, Task details found, 97 00:04:18,089 --> 00:04:20,413 comma, editing task, $, 98 00:04:21,610 --> 00:04:25,523 left and right curly braces and we'll go with task.id. 99 00:04:27,870 --> 00:04:28,860 And we're going to ignore the 100 00:04:28,860 --> 00:04:30,500 error that you see there for task, 101 00:04:30,500 --> 00:04:32,550 and we'll get a few of those errors as we type this in, 102 00:04:32,550 --> 00:04:35,240 and I'll explain that a little bit later in the video. 103 00:04:35,240 --> 00:04:37,723 Alright, next line, addedit_name.setText, 104 00:04:40,070 --> 00:04:42,420 we're setting the text for the widget, 105 00:04:42,420 --> 00:04:45,183 and it's going to be task.name. 106 00:04:46,880 --> 00:04:51,083 Addedit_description.setText, 107 00:04:52,980 --> 00:04:54,160 parentheses for that, will be 108 00:04:54,160 --> 00:04:57,700 task.description in parentheses. 109 00:04:57,700 --> 00:04:58,533 Then the third line, 110 00:04:58,533 --> 00:05:03,533 addedit_sortorder.setText again, 111 00:05:03,900 --> 00:05:06,800 parentheses, and within the parentheses, Integer.toString, 112 00:05:11,550 --> 00:05:14,907 and in parentheses, it'll be task.sortOrder. 113 00:05:18,362 --> 00:05:20,250 Alright, so that's the code, if task isn't null, 114 00:05:20,250 --> 00:05:23,370 else, the code block for else will be, 115 00:05:23,370 --> 00:05:25,210 we'll just put a comment here so we know what we're doing. 116 00:05:25,210 --> 00:05:27,993 So basically no task, so we must be adding a new task, 117 00:05:34,420 --> 00:05:36,020 and not editing an existing one. 118 00:05:38,760 --> 00:05:40,020 So we'll just add a log at this stage, 119 00:05:40,020 --> 00:05:42,850 Log.d, parentheses TAG comma, 120 00:05:42,850 --> 00:05:44,103 double quotes, onViewCreated, 121 00:05:45,880 --> 00:05:48,693 colon No arguments, 122 00:05:49,720 --> 00:05:50,620 adding new record. 123 00:05:52,810 --> 00:05:55,650 Alright, so that's pretty straightforward and simple code. 124 00:05:55,650 --> 00:05:59,300 We're just displaying the task details if there is a task. 125 00:05:59,300 --> 00:06:01,780 It's a bit of a waste of time doing that if the details 126 00:06:01,780 --> 00:06:04,400 are only going to be replaced by the user's edits. 127 00:06:04,400 --> 00:06:07,390 Fortunately, we know about the fragment life cycle 128 00:06:07,390 --> 00:06:10,070 and we know that the savedInstanceState argument 129 00:06:10,070 --> 00:06:12,160 for this method will be null when 130 00:06:12,160 --> 00:06:13,850 the fragment's first created. 131 00:06:13,850 --> 00:06:16,760 Then after that, after our rotation for example, 132 00:06:16,760 --> 00:06:18,730 the savedInstanceState bundle will contain 133 00:06:18,730 --> 00:06:21,500 the data from the edit text widgets. 134 00:06:21,500 --> 00:06:23,450 We can check that and then only populate 135 00:06:23,450 --> 00:06:25,890 the widgets ourselves if that's necessary. 136 00:06:25,890 --> 00:06:27,580 So let's add the code to do that. 137 00:06:27,580 --> 00:06:29,393 We want to surround our other code, 138 00:06:30,470 --> 00:06:32,360 so if parentheses, and it's going to be 139 00:06:32,360 --> 00:06:34,903 savedInstanceState is not equal to null, 140 00:06:36,780 --> 00:06:39,880 closing parentheses, at the left curly brace, 141 00:06:39,880 --> 00:06:42,530 I'm going to add the right curly brace down here 142 00:06:42,530 --> 00:06:45,210 right just before the end of the function, 143 00:06:45,210 --> 00:06:46,820 we should indent everything nicely. 144 00:06:46,820 --> 00:06:48,570 Alright, so I've now wrapped that in that test 145 00:06:48,570 --> 00:06:51,713 to see whether savedInstanceState is not equal to null. 146 00:06:51,713 --> 00:06:52,760 And in fact, that should have been 147 00:06:52,760 --> 00:06:54,993 if savedInstanceState is equal to null, 148 00:06:56,729 --> 00:06:58,300 because again, what we're trying to do, 149 00:06:58,300 --> 00:07:02,280 we know that savedInstanceState argument will be null 150 00:07:02,280 --> 00:07:03,970 when the fragment's first created. 151 00:07:03,970 --> 00:07:05,850 So what we're doing a test for here 152 00:07:05,850 --> 00:07:09,070 is if it is null, in other words if it's first created, 153 00:07:09,070 --> 00:07:10,670 then we're grabbing the data 154 00:07:10,670 --> 00:07:13,250 and populating the various widgets. 155 00:07:13,250 --> 00:07:15,090 And this also saves processing, which is 156 00:07:15,090 --> 00:07:17,270 kinder on our user's batteries. 157 00:07:17,270 --> 00:07:18,930 Alright, so we've got those errors that I mentioned 158 00:07:18,930 --> 00:07:21,610 when I referred to task in the code. 159 00:07:21,610 --> 00:07:24,300 This is a more extreme example of the problem 160 00:07:24,300 --> 00:07:26,230 I referred to in a previous video, 161 00:07:26,230 --> 00:07:29,570 when we tried to cast the listener to AppCompatActivity, 162 00:07:29,570 --> 00:07:32,323 and the error is if I go over any of these references. 163 00:07:33,320 --> 00:07:35,880 Smart cast to Task is impossible because Task 164 00:07:35,880 --> 00:07:37,450 is a mutable property that could 165 00:07:37,450 --> 00:07:39,860 have been changed by this time. 166 00:07:39,860 --> 00:07:41,280 Now we've just tested for null 167 00:07:41,280 --> 00:07:43,520 and we know that Task won't change. 168 00:07:43,520 --> 00:07:46,010 The Kotlin compiler doesn't know that, though. 169 00:07:46,010 --> 00:07:48,320 Kotlin's been designed to be a very safe language, 170 00:07:48,320 --> 00:07:51,130 and unless the compiler performed a thorough analysis of all 171 00:07:51,130 --> 00:07:54,290 the code, including all the code in the Android framework, 172 00:07:54,290 --> 00:07:56,860 there's no way it can tell that we're doing something safe. 173 00:07:56,860 --> 00:07:58,050 The Kotlin designers aren't going 174 00:07:58,050 --> 00:08:00,480 to add that sort of analysis to the compiler, it would 175 00:08:00,480 --> 00:08:03,850 increase compile time very significantly, for one thing. 176 00:08:03,850 --> 00:08:06,820 So it's up to us to deal with situations like this. 177 00:08:06,820 --> 00:08:08,620 So we could use the bang bang operator. 178 00:08:08,620 --> 00:08:11,710 We know that Task might be modified, so that's one approach. 179 00:08:11,710 --> 00:08:16,410 So if we come up here and add the bang bang operator, 180 00:08:16,410 --> 00:08:18,750 that clears the error and is one approach. 181 00:08:18,750 --> 00:08:20,270 We would have to do that for every line 182 00:08:20,270 --> 00:08:23,240 that the task appears in, so I prefer a different solution, 183 00:08:23,240 --> 00:08:26,100 and that's the solution I mentioned in an earlier video. 184 00:08:26,100 --> 00:08:28,640 Basically creating a local val variable 185 00:08:28,640 --> 00:08:30,630 and assigning Task to that. 186 00:08:30,630 --> 00:08:33,580 So let's do that, within the test for savedInstanceState 187 00:08:34,490 --> 00:08:38,633 being equal to null, val task equals task. 188 00:08:40,730 --> 00:08:42,480 So now the code block's referring to that 189 00:08:42,480 --> 00:08:46,350 local variable, not to the Task argument. 190 00:08:46,350 --> 00:08:48,450 Now we've also got a warning though over here now. 191 00:08:48,450 --> 00:08:50,250 From Android Studio, that the null, 192 00:08:50,250 --> 00:08:52,200 and we'll just go over it, hover over it. 193 00:08:52,200 --> 00:08:54,280 Basically unnecessary non-null assertion 194 00:08:54,280 --> 00:08:56,593 on a non-null receiver of type Task. 195 00:08:57,740 --> 00:09:00,190 So we can just remove the bang bang operator now, 196 00:09:01,380 --> 00:09:03,290 and that fixes that warning. 197 00:09:03,290 --> 00:09:04,730 But I've also got another warning here 198 00:09:04,730 --> 00:09:09,060 on line 54, about number formatting, and specifically, 199 00:09:09,060 --> 00:09:11,900 it doesn't take into account locale settings. 200 00:09:11,900 --> 00:09:13,910 If we were dealing with numbers that had decimal points, 201 00:09:13,910 --> 00:09:16,520 we would certainly take that warning seriously. 202 00:09:16,520 --> 00:09:18,330 Europe, for example, uses a comma 203 00:09:18,330 --> 00:09:20,250 instead of a dot for the decimal point, 204 00:09:20,250 --> 00:09:23,780 and a dot instead of a comma for the thousand separator. 205 00:09:23,780 --> 00:09:25,890 But here we're only dealing with integer values, 206 00:09:25,890 --> 00:09:27,770 without thousand separators, and there's 207 00:09:27,770 --> 00:09:31,440 no need to consider localization in this particular case. 208 00:09:31,440 --> 00:09:33,390 The easiest way to remove that warning 209 00:09:33,390 --> 00:09:36,070 is just to use the light bulb to suppress it. 210 00:09:36,070 --> 00:09:37,970 So depending on where you are on the line, 211 00:09:37,970 --> 00:09:39,620 we should be able to click into there, 212 00:09:39,620 --> 00:09:41,280 and the light bulb will appear, 213 00:09:41,280 --> 00:09:43,680 but it's very much depending on where you're clicking 214 00:09:43,680 --> 00:09:47,600 before we get the right way to suppress it. 215 00:09:47,600 --> 00:09:50,070 So I can click into the left parentheses, 216 00:09:50,070 --> 00:09:52,630 is usually a good option, and that now works. 217 00:09:52,630 --> 00:09:55,010 We've now got the suppress message come up, 218 00:09:55,010 --> 00:09:58,870 and we can click on that, and we get, on line 47, 219 00:09:58,870 --> 00:10:02,000 an annotation above the onViewCreated function, 220 00:10:02,000 --> 00:10:04,710 and that warning has now disappeared as a result. 221 00:10:04,710 --> 00:10:07,380 Alright, so that's the first part of the UI done. 222 00:10:07,380 --> 00:10:09,160 In the next video, we will need to 223 00:10:09,160 --> 00:10:11,620 add the code to the save button's listener 224 00:10:11,620 --> 00:10:14,110 to save the details to the database. 225 00:10:14,110 --> 00:10:15,410 See you in the next video.