1 00:00:03,650 --> 00:00:06,689 So this video will be a challenge to fix 2 00:00:06,689 --> 00:00:09,030 a bug in the calculator app, so we're 3 00:00:09,030 --> 00:00:11,250 gonna start by demonstrating that bug. So 4 00:00:11,250 --> 00:00:12,570 you can see that I've got the calculator 5 00:00:12,570 --> 00:00:14,969 app running on an emulator. Now the way 6 00:00:14,969 --> 00:00:17,789 that this app works, the arithmetic 7 00:00:17,789 --> 00:00:20,609 operation keys will cause the previous 8 00:00:20,609 --> 00:00:22,650 calculation to be performed, and then 9 00:00:22,650 --> 00:00:24,269 become the next operation to be 10 00:00:24,269 --> 00:00:26,189 performed. So this is done by storing 11 00:00:26,189 --> 00:00:28,560 the operation in the pendingOperation 12 00:00:28,560 --> 00:00:30,840 variable - as we saw when writing the code 13 00:00:30,840 --> 00:00:32,820 in previous videos. Now if you 14 00:00:32,820 --> 00:00:34,800 accidentally press an incorrect 15 00:00:34,800 --> 00:00:37,320 operation key when the input is empty, 16 00:00:37,320 --> 00:00:39,270 you can correct it by pressing the 17 00:00:39,270 --> 00:00:42,180 correct one - and you can see the 18 00:00:42,180 --> 00:00:43,890 operation change on the screen as I 19 00:00:43,890 --> 00:00:46,590 press each one. So to see the bug, I'm 20 00:00:46,590 --> 00:00:48,120 starting afresh so I don't need to clear 21 00:00:48,120 --> 00:00:50,430 anything, but just to make sure, I'm going 22 00:00:50,430 --> 00:00:52,379 to press, to clear rather, the pending 23 00:00:52,379 --> 00:00:54,989 operation by pressing equals. Then I'm 24 00:00:54,989 --> 00:01:02,059 going to enter 57 equals, then minus 6, 25 00:01:02,059 --> 00:01:08,159 and then multiply. So the result of 51 is 26 00:01:08,159 --> 00:01:10,260 displayed, and the next number that I 27 00:01:10,260 --> 00:01:14,130 enter should multiply 51. But, before 28 00:01:14,130 --> 00:01:15,479 entering another number, I'm going to 29 00:01:15,479 --> 00:01:16,979 rotate the device. So I'm gonna go into 30 00:01:16,979 --> 00:01:21,000 landscape mode. Now if I want to multiply 31 00:01:21,000 --> 00:01:24,869 51 by 2, I should just be able to do 2 32 00:01:24,869 --> 00:01:29,700 equals - so 2 equals. Now that didn't go well. 33 00:01:29,700 --> 00:01:32,009 So the problem is that although the 34 00:01:32,009 --> 00:01:34,439 contents of the EditText widget 35 00:01:34,439 --> 00:01:36,689 survive a rotation, none of the app's 36 00:01:36,689 --> 00:01:39,360 variables do. So the activity is 37 00:01:39,360 --> 00:01:42,119 destroyed and recreated when the device 38 00:01:42,119 --> 00:01:44,250 is rotated, remember, so the pending 39 00:01:44,250 --> 00:01:46,740 Operation variable is reset to 40 00:01:46,740 --> 00:01:50,189 equals. Alright, so the challenge is to 41 00:01:50,189 --> 00:01:52,290 fix the bug, by storing and retrieving 42 00:01:52,290 --> 00:01:55,219 the app's state when the device is rotated. 43 00:01:55,219 --> 00:01:57,630 Now if you're not sure how to do this, or 44 00:01:57,630 --> 00:01:59,729 to how to approach it, review the last 45 00:01:59,729 --> 00:02:02,549 videos in section 5, where I discussed 46 00:02:02,549 --> 00:02:04,979 the Activity Lifecycle, and where we 47 00:02:04,979 --> 00:02:07,500 saved the contents of the TextView for 48 00:02:07,500 --> 00:02:09,750 the Button Click App. Alright, so pause 49 00:02:09,750 --> 00:02:12,120 the video here, and when you've had a go 50 00:02:12,120 --> 00:02:13,290 at that and you're ready to come back 51 00:02:13,290 --> 00:02:13,830 and see the 52 00:02:13,830 --> 00:02:15,810 solution, you can start the 53 00:02:15,810 --> 00:02:17,220 video and I'll go through and do that. So 54 00:02:17,220 --> 00:02:19,349 pause the video now. 55 00:02:19,349 --> 00:02:21,290 Alright, so let's look at the solution. 56 00:02:21,290 --> 00:02:24,060 So the methods we need to Override to 57 00:02:24,060 --> 00:02:26,700 store state are onSaveInstanceState 58 00:02:26,700 --> 00:02:29,370 and onRestoreInstanceState. And as 59 00:02:29,370 --> 00:02:30,959 a reminder, here's the Activity Lifecycle 60 00:02:30,959 --> 00:02:33,749 slide from section five. 61 00:02:33,749 --> 00:02:37,590 Now onSaveInstanceState is called if 62 00:02:37,590 --> 00:02:39,870 needed, when Android's about to destroy 63 00:02:39,870 --> 00:02:41,639 the Activity - as it does when the 64 00:02:41,639 --> 00:02:43,920 orientation changes. So now that we've 65 00:02:43,920 --> 00:02:46,379 created a separate layout for landscape 66 00:02:46,379 --> 00:02:49,019 mode, the reason why Android destroys and 67 00:02:49,019 --> 00:02:51,299 recreates the activity may make more 68 00:02:51,299 --> 00:02:53,310 sense now. And it's because it's an entire new 69 00:02:53,310 --> 00:02:55,889 layout that has to be applied, and the 70 00:02:55,889 --> 00:02:57,930 easiest and safest way to do that is to 71 00:02:57,930 --> 00:03:00,389 just start again. So with all these 72 00:03:00,389 --> 00:03:02,219 challenges, there's often more than one 73 00:03:02,219 --> 00:03:04,409 way to solve them. The real test here is 74 00:03:04,409 --> 00:03:05,189 Does it work? 75 00:03:05,189 --> 00:03:07,500 and definitely not Does your code look 76 00:03:07,500 --> 00:03:10,590 the same as mine? Alright, so state can 77 00:03:10,590 --> 00:03:12,810 be restored in either onCreate or on 78 00:03:12,810 --> 00:03:15,180 RestoreInstanceState, and I'm going to 79 00:03:15,180 --> 00:03:17,669 use onRestoreInstanceState. But if 80 00:03:17,669 --> 00:03:20,040 your solution used onCreate, that's fine. 81 00:03:20,040 --> 00:03:22,469 The reason I prefer not to restore state 82 00:03:22,469 --> 00:03:25,109 in there - in onCreate - is mainly 83 00:03:25,109 --> 00:03:27,209 because it's a good idea to keep the 84 00:03:27,209 --> 00:03:29,340 code in a separate method, just to keep 85 00:03:29,340 --> 00:03:32,340 things easier to understand. In addition, 86 00:03:32,340 --> 00:03:34,500 if you try to use the Bundle in 87 00:03:34,500 --> 00:03:36,389 onCreate, you have to check that it isn't 88 00:03:36,389 --> 00:03:36,900 null. 89 00:03:36,900 --> 00:03:39,329 Now if there was no saved state, then 90 00:03:39,329 --> 00:03:41,370 Bundle will be null there, whereas on 91 00:03:41,370 --> 00:03:43,229 RestoreInstanceState is only ever 92 00:03:43,229 --> 00:03:44,759 called if there is a valid bundle. 93 00:03:44,759 --> 00:03:46,859 Alright, so let's go back to Android 94 00:03:46,859 --> 00:03:48,780 Studio for my solution to fixing this 95 00:03:48,780 --> 00:03:50,260 bug. 96 00:03:50,260 --> 00:03:52,900 Alright, so a bundle contains a list of 97 00:03:52,900 --> 00:03:55,810 pairs of keys and values, so we need keys 98 00:03:55,810 --> 00:03:57,849 to store the pendingOperation and 99 00:03:57,849 --> 00:04:00,519 operand1 variables under, to enable us to 100 00:04:00,519 --> 00:04:02,620 get them back again. Now because we'll be 101 00:04:02,620 --> 00:04:04,239 using the same keys in two different 102 00:04:04,239 --> 00:04:06,970 places, I'm gonna store them in two constants. 103 00:04:06,970 --> 00:04:09,580 Now unlike Java, where everything must 104 00:04:09,580 --> 00:04:12,190 exist inside a class, Kotlin allows 105 00:04:12,190 --> 00:04:14,379 variables to be declared at the top level 106 00:04:14,379 --> 00:04:17,139 of the file, outside of the class. In fact, 107 00:04:17,139 --> 00:04:19,540 for val constraints, it insists on this. 108 00:04:19,540 --> 00:04:21,820 So if I tried to put this next piece of 109 00:04:21,820 --> 00:04:23,560 code that I'm about to type, inside the 110 00:04:23,560 --> 00:04:25,479 MainActivity class, we'd actually get 111 00:04:25,479 --> 00:04:27,190 an error. Alright, so let's go back up 112 00:04:27,190 --> 00:04:30,280 to the top of MainActivity, and we want 113 00:04:30,280 --> 00:04:31,919 to put this before the class definition. So 114 00:04:31,919 --> 00:04:35,320 I'm gonna start on line 10, and I'm going 115 00:04:35,320 --> 00:04:39,010 to type private const val, and in 116 00:04:39,010 --> 00:04:42,240 uppercase, STATE_PENDING 117 00:04:42,240 --> 00:04:45,820 _OPERATION is equal to, and in 118 00:04:45,820 --> 00:04:50,380 double quotes, PendingOperation. Then 119 00:04:50,380 --> 00:04:56,979 private Const val STATE_ 120 00:04:56,979 --> 00:05:00,340 OPERAND1 equal to, double quotes 121 00:05:00,340 --> 00:05:01,889 Operand1. 122 00:05:01,889 --> 00:05:04,389 Now the actual contents of those strings 123 00:05:04,389 --> 00:05:06,160 can be pretty much anything, but there's 124 00:05:06,160 --> 00:05:08,050 a limit to how big a bundle can be, so 125 00:05:08,050 --> 00:05:10,419 don't go using incredibly long strings. 126 00:05:10,419 --> 00:05:12,820 And just in case it wasn't obvious when 127 00:05:12,820 --> 00:05:15,130 we discussed this earlier, data is saved 128 00:05:15,130 --> 00:05:17,950 in a Bundle as key/value pairs. So the 129 00:05:17,950 --> 00:05:19,360 keys we'll be using are these two 130 00:05:19,360 --> 00:05:21,370 constants; STATE_PENDING 131 00:05:21,370 --> 00:05:23,380 _OPERATION and STATE_ 132 00:05:23,380 --> 00:05:25,599 OPERAND1. Now when we want to get 133 00:05:25,599 --> 00:05:27,669 the value for operand1, we use the key 134 00:05:27,669 --> 00:05:29,889 STATE_OPERAND1 to 135 00:05:29,889 --> 00:05:31,810 retrieve it, and similarly for the 136 00:05:31,810 --> 00:05:34,419 pending operation. Now saving the 137 00:05:34,419 --> 00:05:36,639 variables is just a case of overriding 138 00:05:36,639 --> 00:05:39,160 onSaveInstanceState using the 139 00:05:39,160 --> 00:05:42,099 shortcut Ctrl-O, or you can get a list of 140 00:05:42,099 --> 00:05:43,630 methods to override from Generate on 141 00:05:43,630 --> 00:05:45,340 the Code menu. Now I'm going to put the 142 00:05:45,340 --> 00:05:47,260 overridden methods at the end of 143 00:05:47,260 --> 00:05:49,180 the code, but before the final curly 144 00:05:49,180 --> 00:05:52,780 brace. I'm gonna go right down to the bottom, just down 145 00:05:52,780 --> 00:05:57,639 here, and I'm going to do a Ctrl-O, and we 146 00:05:57,639 --> 00:05:59,080 want onSaveInstanceState. So I'm just 147 00:05:59,080 --> 00:06:00,250 going to type the first few letters - 148 00:06:00,250 --> 00:06:02,770 onSave. There it is there, onSaveInstance 149 00:06:02,770 --> 00:06:03,760 State, so I'm just going to press 150 00:06:03,760 --> 00:06:06,430 Enter. But before I do that, do be 151 00:06:06,430 --> 00:06:08,260 careful here, because there's two 152 00:06:08,260 --> 00:06:10,960 versions of this function. We want the 153 00:06:10,960 --> 00:06:12,430 one that takes a single argument, 154 00:06:12,430 --> 00:06:14,800 and unfortunately, that appears further 155 00:06:14,800 --> 00:06:16,870 down the list than the one that we don't 156 00:06:16,870 --> 00:06:18,190 want - the one that I've actually 157 00:06:18,190 --> 00:06:20,050 currently highlighted. So I'm going to 158 00:06:20,050 --> 00:06:21,490 use the down arrow key to move to the 159 00:06:21,490 --> 00:06:24,760 second definition. So you can see the 160 00:06:24,760 --> 00:06:25,990 second definition there, has only got 161 00:06:25,990 --> 00:06:28,540 just the one argument - outState, which is a 162 00:06:28,540 --> 00:06:33,360 Bundle. Alright, I'm gonna press Enter. And 163 00:06:33,360 --> 00:06:35,680 there's a slight oddity about this 164 00:06:35,680 --> 00:06:37,690 function, to do with the interoperability 165 00:06:37,690 --> 00:06:39,850 with Java, and I'm gonna come back to 166 00:06:39,850 --> 00:06:42,400 that in a minute. But first we need to 167 00:06:42,400 --> 00:06:44,800 add our variables to the bundle, so the 168 00:06:44,800 --> 00:06:46,570 overridden function is going to become 169 00:06:46,570 --> 00:06:48,340 as follows; so we're gonna leave the 170 00:06:48,340 --> 00:06:49,870 first call to super.onSave 171 00:06:49,870 --> 00:06:51,730 InstanceState. And then we're going to 172 00:06:51,730 --> 00:06:56,410 append to that, if parentheses operand 173 00:06:56,410 --> 00:07:02,050 one is not equal to null, in code block. 174 00:07:02,050 --> 00:07:05,800 We're going to do outState.put 175 00:07:05,800 --> 00:07:08,920 Double parentheses, and it's going to be 176 00:07:08,920 --> 00:07:10,810 STATE_OPERAND1 comma 177 00:07:10,810 --> 00:07:14,740 space and operand1 and bang bang - so 178 00:07:14,740 --> 00:07:18,250 two exclamation marks. Now we actually get 179 00:07:18,250 --> 00:07:19,660 an error there - we'll talk about that 180 00:07:19,660 --> 00:07:21,700 shortly. And then I'm going to put on the 181 00:07:21,700 --> 00:07:23,680 line after, outside the closing code 182 00:07:23,680 --> 00:07:28,300 block, outState.putString and STATE 183 00:07:28,300 --> 00:07:31,390 _PENDING_OPERATION comma 184 00:07:31,390 --> 00:07:34,780 space pendingOperation. So notice that 185 00:07:34,780 --> 00:07:36,520 we have to check, firstly, that operand 186 00:07:36,520 --> 00:07:38,770 1 isn't null, otherwise the program would 187 00:07:38,770 --> 00:07:41,020 crash if the device is rotated, before 188 00:07:41,020 --> 00:07:42,910 any numbers had been entered. Alright, 189 00:07:42,910 --> 00:07:44,560 so we've got this error at the moment, on 190 00:07:44,560 --> 00:07:47,950 line 113. And if we hover over that; 191 00:07:47,950 --> 00:07:50,470 Only safe or none-null asserted calls are 192 00:07:50,470 --> 00:07:52,630 allowed on a nullable receiver of type 193 00:07:52,630 --> 00:07:53,370 Bundle. 194 00:07:53,370 --> 00:07:56,020 Now if you haven't got that error, please 195 00:07:56,020 --> 00:07:57,430 keep watching and I'm going to explain 196 00:07:57,430 --> 00:08:00,220 why you haven't. So the problem is that 197 00:08:00,220 --> 00:08:03,250 the outState parameter is of type 198 00:08:03,250 --> 00:08:05,620 Bundle? which is a nullable 199 00:08:05,620 --> 00:08:08,140 Bundle. Now Kotlin doesn't allow method 200 00:08:08,140 --> 00:08:09,820 calls to be made on objects that could 201 00:08:09,820 --> 00:08:11,770 be null. That's a classic problem that 202 00:08:11,770 --> 00:08:13,750 causes Null Pointer Exceptions, and 203 00:08:13,750 --> 00:08:16,300 Kotlin actually makes sure we don't get 204 00:08:16,300 --> 00:08:17,470 those anymore - or at least 205 00:08:17,470 --> 00:08:19,600 it does its best. We can still get them 206 00:08:19,600 --> 00:08:21,160 if we go using the bang bang operator, 207 00:08:21,160 --> 00:08:22,960 which we shouldn't, for example. 208 00:08:22,960 --> 00:08:25,720 So using bang bang is one possible 209 00:08:25,720 --> 00:08:28,060 solution. So in other words, I could come 210 00:08:28,060 --> 00:08:33,280 back up to here, two exclamation marks - 211 00:08:33,280 --> 00:08:35,140 the bang bang. But what we're doing is 212 00:08:35,140 --> 00:08:38,020 asserting that outState won't be null. 213 00:08:38,020 --> 00:08:40,120 Can we be really sure that it can't be 214 00:08:40,120 --> 00:08:42,700 null? Well actually, yes we can. The reason 215 00:08:42,700 --> 00:08:45,220 is that onSaveInstanceState is only 216 00:08:45,220 --> 00:08:47,680 called if there's a Bundle to save. In 217 00:08:47,680 --> 00:08:49,510 fact, you may well not have that error. 218 00:08:49,510 --> 00:08:52,960 Google are adding the @NonNull 219 00:08:52,960 --> 00:08:55,060 annotations to the Android framework 220 00:08:55,060 --> 00:08:57,550 code all the time. And if they mark out 221 00:08:57,550 --> 00:09:00,340 State as NonNull, then Kotlin will be able to 222 00:09:00,340 --> 00:09:02,620 use a non-nullable Bundle type, instead 223 00:09:02,620 --> 00:09:04,270 of this Bundle? that it's 224 00:09:04,270 --> 00:09:08,140 using as the argument on line 110. So 225 00:09:08,140 --> 00:09:10,600 bang bang is one option, but Kotlin also 226 00:09:10,600 --> 00:09:12,550 provides another operator, that I think's 227 00:09:12,550 --> 00:09:14,770 more appropriate here. So let's go 228 00:09:14,770 --> 00:09:17,050 back and replace the double bang with a 229 00:09:17,050 --> 00:09:19,540 safe call operator, which is the question 230 00:09:19,540 --> 00:09:21,040 mark. So we're gonna go back and delete 231 00:09:21,040 --> 00:09:23,200 that - the bang bang - and replace that with 232 00:09:23,200 --> 00:09:25,870 the question mark. So that also fixes the 233 00:09:25,870 --> 00:09:27,910 error, and actually is a safer way to 234 00:09:27,910 --> 00:09:30,520 deal with this. So that applies probably 235 00:09:30,520 --> 00:09:32,560 everywhere that you're accessing a 236 00:09:32,560 --> 00:09:34,690 property or calling a method, on an 237 00:09:34,690 --> 00:09:37,210 object that's of a nullable type. So 238 00:09:37,210 --> 00:09:39,430 whereas bang bang asserts that the 239 00:09:39,430 --> 00:09:41,920 object can't be null, and throws an 240 00:09:41,920 --> 00:09:43,900 exception if it is, the safe call 241 00:09:43,900 --> 00:09:46,030 operator won't actually make the call if 242 00:09:46,030 --> 00:09:48,400 the object is null. So in our code here, 243 00:09:48,400 --> 00:09:50,710 putDouble just won't be called if out 244 00:09:50,710 --> 00:09:52,870 State is null. So that line will just do 245 00:09:52,870 --> 00:09:56,170 nothing. So that's a safer solution than 246 00:09:56,170 --> 00:09:58,210 the double bang operator, and I suggest 247 00:09:58,210 --> 00:10:00,280 you try to use the safe call operator in 248 00:10:00,280 --> 00:10:02,530 these situations. Now it doesn't really 249 00:10:02,530 --> 00:10:04,990 matter here, because we know that out 250 00:10:04,990 --> 00:10:07,510 State won't be null, but safe call can be 251 00:10:07,510 --> 00:10:09,700 used even when you can't be sure. And 252 00:10:09,700 --> 00:10:11,800 we'll see that used again throughout the 253 00:10:11,800 --> 00:10:13,720 course so, you'll get a feel for when 254 00:10:13,720 --> 00:10:15,820 it's a good way to deal with nullable 255 00:10:15,820 --> 00:10:18,490 objects. Okay, so there's a third approach 256 00:10:18,490 --> 00:10:20,680 that can be used here. Now before I 257 00:10:20,680 --> 00:10:22,839 change the code to use it, I should 258 00:10:22,839 --> 00:10:24,190 really point out that you need to 259 00:10:24,190 --> 00:10:26,380 be very careful when using this approach. 260 00:10:26,380 --> 00:10:28,089 So don't go using this approach 261 00:10:28,089 --> 00:10:29,260 indiscriminately. 262 00:10:29,260 --> 00:10:30,940 You need to be very sure that you 263 00:10:30,940 --> 00:10:31,329 understand 264 00:10:31,329 --> 00:10:33,399 what you're doing. So what I'm going 265 00:10:33,399 --> 00:10:36,579 to do is modify the function signature, 266 00:10:36,579 --> 00:10:39,579 so that it accepts a non-null Bundle 267 00:10:39,579 --> 00:10:41,980 argument. So the way to do that is to get 268 00:10:41,980 --> 00:10:45,220 rid of the question mark from the Bundle 269 00:10:45,220 --> 00:10:48,790 type, and once I've done that, I can 270 00:10:48,790 --> 00:10:51,489 actually get rid of the safe, the safe 271 00:10:51,489 --> 00:10:55,449 call operator, like so. Now I can't 272 00:10:55,449 --> 00:10:57,309 predict the future, but it wouldn't 273 00:10:57,309 --> 00:10:59,199 surprise me if this function signature 274 00:10:59,199 --> 00:11:01,569 gets generated automatically, before too 275 00:11:01,569 --> 00:11:03,970 long. It may even be the code that you've 276 00:11:03,970 --> 00:11:05,319 got, if you're watching this video 277 00:11:05,319 --> 00:11:08,470 sometime after I recorded it. As I said, 278 00:11:08,470 --> 00:11:09,879 you do need to be careful when using 279 00:11:09,879 --> 00:11:12,009 this, though. If you're absolutely sure 280 00:11:12,009 --> 00:11:14,379 that outState really will be an 281 00:11:14,379 --> 00:11:16,869 non-nullable type, then this is perfectly 282 00:11:16,869 --> 00:11:18,910 valid. But changing the function 283 00:11:18,910 --> 00:11:21,339 signatures of overridden methods mustn't 284 00:11:21,339 --> 00:11:23,259 be done without fully understanding what 285 00:11:23,259 --> 00:11:26,589 you're doing. So this is the approach I'm 286 00:11:26,589 --> 00:11:29,290 going to take in this app. Now one reason 287 00:11:29,290 --> 00:11:30,879 is that you'll already find code like 288 00:11:30,879 --> 00:11:33,009 this out there. People are already doing 289 00:11:33,009 --> 00:11:34,509 this, and although I haven't yet found an 290 00:11:34,509 --> 00:11:37,029 example of Google doing it, with onSave 291 00:11:37,029 --> 00:11:38,769 InstanceState, there may well be 292 00:11:38,769 --> 00:11:40,419 examples by the time you watch this 293 00:11:40,419 --> 00:11:44,169 video. Now restoring the variable is done 294 00:11:44,169 --> 00:11:46,419 by reading it from a bundle, and I'm also 295 00:11:46,419 --> 00:11:48,369 going to update the display so that the 296 00:11:48,369 --> 00:11:50,579 user can see which operation is pending. 297 00:11:50,579 --> 00:11:53,379 Once again, though, be careful, because 298 00:11:53,379 --> 00:11:55,629 there's an overloaded version of the on 299 00:11:55,629 --> 00:11:58,149 RestoreInstanceState method too. So we 300 00:11:58,149 --> 00:11:59,410 want the one that accepts a single 301 00:11:59,410 --> 00:12:01,360 Bundle argument, and I'm just going to 302 00:12:01,360 --> 00:12:03,579 generate it, just after this onSave 303 00:12:03,579 --> 00:12:06,669 InstanceState function. Let's go ahead 304 00:12:06,669 --> 00:12:11,919 and do that, doing a search for onRestore 305 00:12:11,919 --> 00:12:14,379 and notice we've got the two definitions 306 00:12:14,379 --> 00:12:15,819 there. We actually want the top one - the one 307 00:12:15,819 --> 00:12:17,410 that's just got the Bundle argument and 308 00:12:17,410 --> 00:12:19,839 not the second argument. So I'm going to 309 00:12:19,839 --> 00:12:22,209 press ENTER there. And what I'm going to 310 00:12:22,209 --> 00:12:25,059 do here is take the same approach as for 311 00:12:25,059 --> 00:12:27,160 onSaveInstanceState, and change the 312 00:12:27,160 --> 00:12:30,009 parameter to be a non-nullable Bundle. So 313 00:12:30,009 --> 00:12:32,199 we're going to get rid of the question 314 00:12:32,199 --> 00:12:36,790 mark on the type. Alright, so after the 315 00:12:36,790 --> 00:12:39,160 super.onRestoreInstanceState line, 316 00:12:39,160 --> 00:12:41,740 we need to restore our two properties 317 00:12:41,740 --> 00:12:43,000 from the Bundle, 318 00:12:43,000 --> 00:12:45,250 and then display the operation in its 319 00:12:45,250 --> 00:12:47,350 TextView. So I'm going to start by 320 00:12:47,350 --> 00:12:51,190 typing operand1 is equal to saved 321 00:12:51,190 --> 00:12:56,410 InstanceState.getDouble, and the 322 00:12:56,410 --> 00:12:57,490 argument's gonna be STATE 323 00:12:57,490 --> 00:13:00,450 _OPERAND1 for our const. And 324 00:13:00,450 --> 00:13:05,380 then pendingOperation equals saved 325 00:13:05,380 --> 00:13:09,430 InstanceState.getString, and the 326 00:13:09,430 --> 00:13:10,960 argument is STATE_PENDING 327 00:13:10,960 --> 00:13:13,810 _OPERATION, our constant definition. Then 328 00:13:13,810 --> 00:13:15,070 lastly, as I mentioned, we're going to 329 00:13:15,070 --> 00:13:16,450 display the operation. So it's going to 330 00:13:16,450 --> 00:13:20,100 be displayOperation.text is equal to 331 00:13:20,100 --> 00:13:23,470 pendingOperation. Now that looks fairly 332 00:13:23,470 --> 00:13:25,780 straightforward, but it's important to 333 00:13:25,780 --> 00:13:27,550 check the documentation for any methods 334 00:13:27,550 --> 00:13:29,140 that you use, so that you really 335 00:13:29,140 --> 00:13:31,750 understand how they behave. Now we can do 336 00:13:31,750 --> 00:13:33,910 that in Android Studio, by clicking on 337 00:13:33,910 --> 00:13:35,230 the function that we're interested in, 338 00:13:35,230 --> 00:13:37,750 and using Ctrl-Q on Windows or Linux, and 339 00:13:37,750 --> 00:13:40,240 on a Mac, it's actually Ctrl-J. So we're gonna go 340 00:13:40,240 --> 00:13:42,930 ahead and do that - and this is for the get 341 00:13:42,930 --> 00:13:46,690 Double. And we're gonna come up here and 342 00:13:46,690 --> 00:13:48,850 press my key, and there's the 343 00:13:48,850 --> 00:13:50,770 documentation that's popped up. Again, 344 00:13:50,770 --> 00:13:52,720 it's a Ctrl-Q on Windows or Linux, or 345 00:13:52,720 --> 00:13:56,110 Ctrl-J on a Mac. So the documentation is 346 00:13:56,110 --> 00:13:58,240 short, but it does state that the 347 00:13:58,240 --> 00:14:01,210 function will return 0.0 if the key 348 00:14:01,210 --> 00:14:03,400 doesn't exist in the Bundle. Well 349 00:14:03,400 --> 00:14:07,180 actually, it says or 0.0 if no mapping of 350 00:14:07,180 --> 00:14:08,890 the desired type exists for the given 351 00:14:08,890 --> 00:14:11,080 key, which essentially, means the same 352 00:14:11,080 --> 00:14:13,420 thing. So if a key with the value of 353 00:14:13,420 --> 00:14:15,490 STATE_OPERAND1 doesn't 354 00:14:15,490 --> 00:14:17,530 exist in the Bundle, or if it does exist 355 00:14:17,530 --> 00:14:19,720 but its value isn't a Double, then 356 00:14:19,720 --> 00:14:22,450 operand1 will be given the value 0.0. 357 00:14:22,450 --> 00:14:24,700 Well, that's not actually quite what we 358 00:14:24,700 --> 00:14:27,280 want. If we haven't stored operand1, 359 00:14:27,280 --> 00:14:29,920 that's because it was null, not because it 360 00:14:29,920 --> 00:14:32,530 was zero. So we do want it to have the value 361 00:14:32,530 --> 00:14:34,870 of null after calling getDouble, if it 362 00:14:34,870 --> 00:14:37,330 doesn't exist. Now we can provide a 363 00:14:37,330 --> 00:14:39,310 default value to the getDouble function, 364 00:14:39,310 --> 00:14:42,610 but unfortunately, that value can't be null. 365 00:14:42,610 --> 00:14:45,070 So the way that I suggest coping with 366 00:14:45,070 --> 00:14:46,870 storing values that may be null in a 367 00:14:46,870 --> 00:14:49,870 Bundle, is to also store a Boolean, to 368 00:14:49,870 --> 00:14:51,490 indicate if there's a value there or not. 369 00:14:51,490 --> 00:14:54,040 And that's probably easier to see than to 370 00:14:54,040 --> 00:14:56,450 describe, so let's get to the code. 371 00:14:56,450 --> 00:15:00,140 So firstly, we need to define another 372 00:15:00,140 --> 00:15:01,550 constant for the key, so I'll go right up 373 00:15:01,550 --> 00:15:03,730 to the top of the file to do that, 374 00:15:03,730 --> 00:15:05,750 remembering that the definition is above 375 00:15:05,750 --> 00:15:08,060 the class definition. This is going to be 376 00:15:08,060 --> 00:15:13,130 private const val. This one we'll call 377 00:15:13,130 --> 00:15:18,770 STATE_OPERAND1_STORED is equal to, 378 00:15:18,770 --> 00:15:20,870 and we'll call this one Operand1 379 00:15:20,870 --> 00:15:24,890 _Stored. So next we need to 380 00:15:24,890 --> 00:15:26,960 change the onSaveInstanceState 381 00:15:26,960 --> 00:15:28,250 function slightly, so let's go down to 382 00:15:28,250 --> 00:15:30,620 the bottom and do that. Now we need to 383 00:15:30,620 --> 00:15:32,300 add some code, so we've got this 384 00:15:32,300 --> 00:15:34,880 code on line 113 checking, to see if 385 00:15:34,880 --> 00:15:37,310 operand1 is not equal to null, and then 386 00:15:37,310 --> 00:15:39,590 we've got it putting a Double there. But what 387 00:15:39,590 --> 00:15:41,150 we're going to do after that line, is add 388 00:15:41,150 --> 00:15:45,410 a new line to put outState.put 389 00:15:45,410 --> 00:15:49,280 Boolean. Then we're going to put STATE_ 390 00:15:49,280 --> 00:15:52,810 OPEERAND1_STORED comma true. 391 00:15:52,810 --> 00:15:54,920 So that's all we need to do for the 392 00:15:54,920 --> 00:15:56,540 onSaveInstanceState function. 393 00:15:56,540 --> 00:15:59,510 Now if operand1 was stored, we can check 394 00:15:59,510 --> 00:16:01,610 the value stored under the key STATE 395 00:16:01,610 --> 00:16:03,560 _OPERAND1_STORED. 396 00:16:03,560 --> 00:16:05,660 And if that's true, then we can call get 397 00:16:05,660 --> 00:16:07,880 Double, otherwise operand1 should be 398 00:16:07,880 --> 00:16:11,030 null. So let's update our onRestore 399 00:16:11,030 --> 00:16:13,160 InstanceState function. And we're going 400 00:16:13,160 --> 00:16:15,110 to make a change here, so after the super 401 00:16:15,110 --> 00:16:17,210 call, we're going to put a call here. 402 00:16:17,210 --> 00:16:19,810 We're going to put - type some code - if 403 00:16:19,810 --> 00:16:24,370 savedInstanceState.getBoolean 404 00:16:24,370 --> 00:16:27,560 STATE_OPERAND1_ 405 00:16:27,560 --> 00:16:32,720 STORED comma space false. I'm going to 406 00:16:32,720 --> 00:16:34,730 open a code block. And what I'm going to 407 00:16:34,730 --> 00:16:36,860 do is put in this line here, this operand 408 00:16:36,860 --> 00:16:39,230 1 equals savedInstanceState.get 409 00:16:39,230 --> 00:16:41,570 Double. That will be in the if code block, 410 00:16:41,570 --> 00:16:44,710 and we'll also have an else here, else, 411 00:16:44,710 --> 00:16:48,980 another code block, operand1 is equal to 412 00:16:48,980 --> 00:16:56,330 null. So now on line 122, we call the get 413 00:16:56,330 --> 00:16:58,610 Boolean method, to retrieve the value 414 00:16:58,610 --> 00:17:00,800 stored with the key STATE_ 415 00:17:00,800 --> 00:17:03,980 OPERAND1_STORED. The call to 416 00:17:03,980 --> 00:17:06,890 getBoolean includes a default value of 417 00:17:06,890 --> 00:17:09,410 false, so if the key isn't present, the 418 00:17:09,410 --> 00:17:10,530 condition will be false. 419 00:17:10,530 --> 00:17:12,780 So only if we saved true with that key, 420 00:17:12,780 --> 00:17:18,000 will line 123 be executed. Otherwise, 421 00:17:18,000 --> 00:17:19,740 operand1 will be set to null, as you 422 00:17:19,740 --> 00:17:22,980 can see on line 125. Now we can lift that 423 00:17:22,980 --> 00:17:24,720 assignment out of the if, just like we 424 00:17:24,720 --> 00:17:27,900 did earlier. If I click over here, I can 425 00:17:27,900 --> 00:17:29,760 click on that, and then the light bulb 426 00:17:29,760 --> 00:17:32,550 comes up and I can click on that. And notice 427 00:17:32,550 --> 00:17:34,020 that I only get that operation when I 428 00:17:34,020 --> 00:17:36,300 did click on that in the gutter. Notice 429 00:17:36,300 --> 00:17:38,280 there, that when I do that, if is 430 00:17:38,280 --> 00:17:39,990 underlined there. You see that just 431 00:17:39,990 --> 00:17:42,090 briefly, so, we could also have just clicked 432 00:17:42,090 --> 00:17:44,340 if to see that come up. We can come back 433 00:17:44,340 --> 00:17:48,690 over here again. There's the light bulb - 434 00:17:48,690 --> 00:17:50,720 click on that, and lift ssignment out of if. 435 00:17:50,720 --> 00:17:52,980 And you can see the code's been changed 436 00:17:52,980 --> 00:17:55,970 for us. And that should now do it for us. 437 00:17:55,970 --> 00:17:58,890 So, let's actually run the app again and 438 00:17:58,890 --> 00:18:00,390 just check that it's actually working, as 439 00:18:00,390 --> 00:18:05,240 we suspect it will, or hope that it will. 440 00:18:05,240 --> 00:18:07,230 Alright, so I'm going to start by doing 441 00:18:07,230 --> 00:18:19,560 equals 57, equals minus 6, times. Now I'm 442 00:18:19,560 --> 00:18:23,070 going to rotate like I did last time, and 443 00:18:23,070 --> 00:18:27,360 then I'm going to type 2 equals. This 444 00:18:27,360 --> 00:18:29,910 time, we got the answer 102 so that's 445 00:18:29,910 --> 00:18:32,790 now working fine. So our calculator now 446 00:18:32,790 --> 00:18:35,040 behaves as expected, even when the 447 00:18:35,040 --> 00:18:37,530 orientation's changed. Now this particular 448 00:18:37,530 --> 00:18:40,320 app has very little state - there's just 449 00:18:40,320 --> 00:18:42,330 the contents of the two EditText widgets, 450 00:18:42,330 --> 00:18:44,730 the content of the displayOperation 451 00:18:44,730 --> 00:18:47,670 TextView, and operand1. Now the two 452 00:18:47,670 --> 00:18:49,410 EditText widgets are saved and 453 00:18:49,410 --> 00:18:52,050 restored for us. Android knows that users 454 00:18:52,050 --> 00:18:54,060 may type text into EditText widgets - 455 00:18:54,060 --> 00:18:55,830 that's what they're there for, after all - 456 00:18:55,830 --> 00:18:58,080 so the Activity's onSaveInstanceState 457 00:18:58,080 --> 00:19:00,330 and onRestoreInstanceState methods, 458 00:19:00,330 --> 00:19:02,430 are taking care of the EditText widgets. 459 00:19:02,430 --> 00:19:04,410 So that's why it's important, looking 460 00:19:04,410 --> 00:19:06,990 back at the code, to leave these super 461 00:19:06,990 --> 00:19:07,920 dot on calls, 462 00:19:07,920 --> 00:19:10,110 super.savedInstanceState on line 463 00:19:10,110 --> 00:19:12,030 112, and super.on 464 00:19:12,030 --> 00:19:16,140 RestoreInstanceState on line 121. So 465 00:19:16,140 --> 00:19:17,490 it's important to leave those in when we 466 00:19:17,490 --> 00:19:19,770 override the onSaveInstanceState and 467 00:19:19,770 --> 00:19:21,990 onRestoreInstanceState functions. So all 468 00:19:21,990 --> 00:19:23,400 we had to do was store and retrieve 469 00:19:23,400 --> 00:19:24,210 the contents of 470 00:19:24,210 --> 00:19:27,450 the TextView, and operand1. This was 471 00:19:27,450 --> 00:19:29,070 complicated slightly, because we're 472 00:19:29,070 --> 00:19:30,990 allowing operand1 to be null, and 473 00:19:30,990 --> 00:19:33,420 Kotlin can't store null in a Bundle. So 474 00:19:33,420 --> 00:19:35,520 we had to use that additional flag, to 475 00:19:35,520 --> 00:19:37,260 let us decide whether operand1 should 476 00:19:37,260 --> 00:19:39,900 be null, when we try to restore it. So 477 00:19:39,900 --> 00:19:41,250 there's still room for improvement, but 478 00:19:41,250 --> 00:19:43,380 before we change the way our Calculator 479 00:19:43,380 --> 00:19:45,180 works, we're going to look at another 480 00:19:45,180 --> 00:19:47,610 method that Kotlin provides, for getting 481 00:19:47,610 --> 00:19:49,710 references to widgets. And we'll do that 482 00:19:49,710 --> 00:19:52,580 in the next video.