1 00:00:03,740 --> 00:00:09,770 G'day everyone, welcome back. At the moment, our About dialogue can only be dismissed 2 00:00:09,770 --> 00:00:14,750 by tapping away from it on the device screen. But it's also usual to dismiss 3 00:00:14,750 --> 00:00:20,029 this type of dialogue by allowing the user to tap the dialogue itself, or by 4 00:00:20,029 --> 00:00:26,020 providing an OK button. We'll look at both ways to implement that, in this video. 5 00:00:26,020 --> 00:00:30,739 I'm going to do both, one after the other, because there's a reason why 6 00:00:30,739 --> 00:00:36,230 tapping the dialogue to dismiss it isn't really appropriate in this case. In fact, 7 00:00:36,230 --> 00:00:41,390 there are two reasons. So we're not going to dismiss the dialogue by tapping on it 8 00:00:41,390 --> 00:00:46,120 in this app, but we'll have a quick look at how to implement that behavior. 9 00:00:46,120 --> 00:00:51,640 We just have to set an onClick listener to the dialogue's view. We've set on click 10 00:00:51,649 --> 00:00:56,210 listeners on buttons and ListView items, but you can add them to any View in 11 00:00:56,210 --> 00:01:01,760 Android. Anything you can display on the screen can be made clickable. 12 00:01:01,760 --> 00:01:07,480 In MainActivity, I'll delete that commented out code that didn't work, because you've got 13 00:01:07,480 --> 00:01:16,700 the source in the last two videos if you need it. 14 00:01:16,700 --> 00:01:20,320 We'll take this line out too, 15 00:01:24,240 --> 00:01:27,439 and then we'll add our listener. 16 00:01:39,750 --> 00:01:44,460 We've seen code like this lots of times now. The difference is that we're setting 17 00:01:44,460 --> 00:01:49,590 a listener on a View this time, rather than a button. That's one way of allowing 18 00:01:49,590 --> 00:01:54,570 the user another way to dismiss the dialogue, but in our particular case, it's 19 00:01:54,570 --> 00:01:59,430 got a couple of problems. I'll run the app to make sure it works and then we'll 20 00:01:59,430 --> 00:02:02,720 look at what those problems are. 21 00:02:10,220 --> 00:02:14,630 With the about dialogue showing, I can click somewhere near the copyright 22 00:02:14,630 --> 00:02:23,170 message and the dialogue's dismissed. We also get the message in logcat; 23 00:02:29,580 --> 00:02:32,780 entering message view dot onClick. 24 00:02:32,780 --> 00:02:35,480 So that's working fine and shows you can 25 00:02:35,490 --> 00:02:41,610 attach onClick listeners to any type of View. The first problem is, that our icon 26 00:02:41,610 --> 00:02:47,370 and title aren't part of our View. They were added by the dialog builder. If we 27 00:02:47,370 --> 00:02:57,340 launch the About dialogue again, and tap near the icon or title, 28 00:02:57,340 --> 00:02:59,060 nothing happens. 29 00:02:59,060 --> 00:03:03,980 The version number's part of our layout, so tapping that will dismiss the dialogue, 30 00:03:03,980 --> 00:03:09,930 but from our user's point of view, it's a bit hit or miss. If you include the title 31 00:03:09,930 --> 00:03:15,780 and icon in the layout, everything would work fine. In that case, this would be a 32 00:03:15,780 --> 00:03:21,660 suitable approach, except for the second problem. We've made the links in the text 33 00:03:21,660 --> 00:03:27,060 clickable. The way that works, is that Android intercepts taps on the entire 34 00:03:27,060 --> 00:03:34,170 line of text, not just on the link itself. If I tap level with the URL, but away to 35 00:03:34,170 --> 00:03:41,260 the right, it's still part of the TextView and we've enabled autoLink on the TextView. 36 00:03:41,260 --> 00:03:45,510 So, I'd suggest that dismissing the dialogue by tapping it, when you're 37 00:03:45,510 --> 00:03:51,040 also showing autoLink text, isn't an ideal way to handle things. 38 00:03:51,040 --> 00:03:56,720 If you're not showing autoLink text and your layout covers the entire dialogue, then the code 39 00:03:56,720 --> 00:03:58,860 you've got will work fine. 40 00:03:58,860 --> 00:04:03,320 OK, let's see how to add a button to the dialogue instead. 41 00:04:03,320 --> 00:04:08,560 I want to leave the current code in, so it's available in the code you can download. 42 00:04:08,560 --> 00:04:15,080 I'll copy the entire function and comment one copy out so it's still available. 43 00:04:15,080 --> 00:04:19,820 Android Studio has a neat feature to make that a lot easier. 44 00:04:19,820 --> 00:04:25,400 Select the entire function, including the annotation at the top, and use ctrl D, 45 00:04:25,410 --> 00:04:28,820 command D on a Mac. 46 00:04:32,400 --> 00:04:37,420 That works better if you also include the blank line after the function. 47 00:04:37,420 --> 00:04:43,800 The copy remains highlighted, so we can use control / (command / on the Mac) 48 00:04:43,800 --> 00:04:49,300 to comment the copy out. We can get the Builder to add a new button to the dialogue. 49 00:04:49,300 --> 00:04:53,260 Just like we had to do with the title and the icon. Though we have to add 50 00:04:53,260 --> 00:04:58,840 the button call before the call to builder.create, otherwise the button won't 51 00:04:58,840 --> 00:05:01,650 appear in the dialogue. 52 00:05:26,440 --> 00:05:32,420 We've seen the setPositive button function before, in our AppDialog class, 53 00:05:32,420 --> 00:05:37,780 and this is doing the same thing. Run the app, and our users can now dismiss the dialogue, 54 00:05:37,780 --> 00:05:43,360 by tapping away from it or tapping the OK button. 55 00:05:58,240 --> 00:06:03,080 So, that's dialogues in a nutshell. They've turned into a large nut, though. 56 00:06:03,080 --> 00:06:07,280 I'm going to finish this video with a comment about that last bit of code. 57 00:06:07,280 --> 00:06:11,920 Looking at the code in the setPositiveButton function that we just 58 00:06:11,920 --> 00:06:18,430 created, we perform a null check and also check that the dialogue is showing, 59 00:06:18,430 --> 00:06:23,919 before calling it's dismiss function. Because Kotlin can't be sure that aboutDialogue 60 00:06:23,920 --> 00:06:29,620 hasn't been changed on another thread, we need to use a safe call operator. 61 00:06:29,620 --> 00:06:33,900 You may be wondering why it's necessary to check that the dialogue's showing before 62 00:06:33,910 --> 00:06:38,110 dismissing it. If the dialogue's not showing, it's going to 63 00:06:38,110 --> 00:06:43,240 be very hard for the user to tap the button. That may be true, but in an 64 00:06:43,240 --> 00:06:48,430 event-driven system like Android, you can never be completely sure about the order 65 00:06:48,430 --> 00:06:53,889 that events happen. If the device is rotated, and the user accidentally taps 66 00:06:53,889 --> 00:06:58,900 the button at just the wrong time, it may be possible for our code to be called, 67 00:06:58,900 --> 00:07:04,840 very slightly after the system's removed the dialogue. We can't be sure that an 68 00:07:04,840 --> 00:07:10,060 event such as garbage collection, or an incoming phone call, won't slow things 69 00:07:10,060 --> 00:07:15,300 down just enough, to give a delay before our function's called. 70 00:07:15,300 --> 00:07:21,480 Trying to duplicate a series of events like that, so you can test it and be completely sure that it 71 00:07:21,490 --> 00:07:26,979 will never happen, is not going to be easy. If an event happens, though, you can 72 00:07:26,979 --> 00:07:31,900 be sure that you've handled it correctly. If something doesn't happen, you can't be 73 00:07:31,900 --> 00:07:35,500 sure that it never will. Just because you can't get it to happen, 74 00:07:35,500 --> 00:07:41,169 doesn't guarantee that it won't. So, I prefer to program very defensively in 75 00:07:41,169 --> 00:07:46,330 these situations. The safe call operator makes sure we don't try to call a 76 00:07:46,330 --> 00:07:53,920 function on a null object. At the moment, the check for isShowing isn't strictly necessary. 77 00:07:53,920 --> 00:07:57,460 If you look at the code for the dismiss function, and follow it back 78 00:07:57,460 --> 00:08:02,320 to the dialogue class dismiss dialogue function, you'll see that there's a check 79 00:08:02,320 --> 00:08:06,849 that the dialogue is showing in there. We're not writing a time critical bit of 80 00:08:06,849 --> 00:08:11,680 code here, and I prefer to be safe, rather than find that Google has 81 00:08:11,680 --> 00:08:17,400 changed something and my code crashes. Alright, I'll accept Android Studio's 82 00:08:17,400 --> 00:08:23,110 suggestion that we can replace the dialogue and the which arguments with an 83 00:08:23,110 --> 00:08:28,500 underscore. In fact, I'll get the light bulb to do that. 84 00:08:35,980 --> 00:08:41,539 You have to get the light bulb to appear twice, once for each argument. 85 00:08:41,539 --> 00:08:46,300 The compiler can optimize the code, if it knows that the arguments aren't used, 86 00:08:46,300 --> 00:08:52,390 and using underscore for the name is how you tell it that. In the next video, we'll see 87 00:08:52,390 --> 00:08:56,720 how to make the links clickable on older Android versions. 88 00:08:56,720 --> 00:08:59,840 See you in the next one.